<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.csclub.uwaterloo.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=K57chan</id>
	<title>CSCWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.csclub.uwaterloo.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=K57chan"/>
	<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/Special:Contributions/K57chan"/>
	<updated>2026-04-06T06:58:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=CloudStack&amp;diff=5383</id>
		<title>CloudStack</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=CloudStack&amp;diff=5383"/>
		<updated>2025-07-01T19:55:27Z</updated>

		<summary type="html">&lt;p&gt;K57chan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;We are using [https://cloudstack.apache.org/ Apache CloudStack] to provide VMs-as-a-service to members. Our user documentation is here: https://docs.cloud.csclub.uwaterloo.ca&lt;br /&gt;
&lt;br /&gt;
Prerequisite reading:&lt;br /&gt;
&lt;br /&gt;
* [[Ceph]]&lt;br /&gt;
* [[Cloud Networking]]&lt;br /&gt;
&lt;br /&gt;
Official CloudStack documentation: http://docs.cloudstack.apache.org/en/4.16.0.0/&lt;br /&gt;
&lt;br /&gt;
== Rebooting machines ==&lt;br /&gt;
I&#039;m going to start with this first because this is what future sysadmins are most interested in. If you reboot one of the CloudStack guest machines (as of this writing: biloba, ginkgo and chamomile), then I suggest you perform a live migration of all of the VMs on that host to the other other machines (see [[#Sequential reboot]]).&lt;br /&gt;
&lt;br /&gt;
If this is not possible (e.g. there is not enough capacity on the other machines), then CloudStack will most likely shut down the VMs automatically. &amp;lt;b&amp;gt;You are responsible for restarting them manually after the reboot.&amp;lt;/b&amp;gt; You will also need to manually restart any Kubernetes clusters.&lt;br /&gt;
&lt;br /&gt;
Note: if the cloudstack-agent.service is having trouble reconnecting to the management servers after a reboot, just do a systemctl restart and cross your fingers.&lt;br /&gt;
&lt;br /&gt;
=== Sequential reboot ===&lt;br /&gt;
If it is possible to reboot the machines one at a time (e.g. for a software upgrade), then it is possible to avoid having any downtime. Login to the web UI as admin, go to Infrastructure &amp;gt; Hosts, hover above the three-dots button for a particular host, then press the &amp;quot;Enable Maintenance Mode&amp;quot; button.&lt;br /&gt;
[[File:Cloudstack-enable-maintenance-mode-button.png|1000px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Wait for the VMs to be migrated to the other machines (press the Refresh button to update the table). If you see an error which says &amp;quot;ErrorInPrepareForMaintenance&amp;quot;, just wait it out. If more than 20 minutes have passed and there is still no progress, take the host out of maintenance mode, and put it back into maintenance mode. If this still does not work, restart the management server.&lt;br /&gt;
&lt;br /&gt;
When a host is in maintenance mode, it should look like this:&lt;br /&gt;
[[File:Cloudstack-host-in-maintenance-mode.png|1000px]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Once all VMs have been migrated, do whatever you need to do on the physical host; once it is back up, take it back out of maintenance mode from the web UI. Repeat for any other hosts which need to be taken offline.&lt;br /&gt;
&lt;br /&gt;
== Unexpected reboot ==&lt;br /&gt;
Sometimes a network interface fails on a machine after the switches in MC are rebooted (looking at you, riboflavin). Or a machine randomly goes offline in the middle of the night (looking at you, ginkgo). Point is, sometimes a machine needs to rebooted, or is forcefully rebooted, without preparation. Unfortunately, &amp;lt;strong&amp;gt;CloudStack is unable to recover gracefully from an unexpected reboot&amp;lt;/strong&amp;gt;. This means that &amp;lt;strong&amp;gt;manual intervention is required&amp;lt;/strong&amp;gt; to get the VMs back into a working state.&lt;br /&gt;
&lt;br /&gt;
Once the machine has come back online, perform the following:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;All of the VMs which were on that machine will eventually transition to the Stopped state. Wait for this to happen first (from the web UI).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Go to Infrastructure -&amp;gt; Management servers and make sure that both biloba and chamomile are present and running. If not, you may need to restart the management server on the machine (&amp;lt;code&amp;gt;systemctl restart cloudstack-management&amp;lt;/code&amp;gt;). Watch the journald logs for any error messages.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Go to Infrastructure -&amp;gt; Hosts and make sure that all three hosts (biloba, chamomile and ginkgo) are present and running. If not, you may need to restart the agent on the machine (&amp;lt;code&amp;gt;systemctl restart cloudstack-agent&amp;lt;/code&amp;gt;). Watch the journald logs for any error messages.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If you restart cloudstack-agent, restart virtlogd as well, just for good measure. Watch the journald logs for any error messages.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Restart ONE of the stopped VMs and make sure that it transitions to the Started state. If more than 20 minutes pass and it still hasn&#039;t started, restart the management servers and try again.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Restart the rest of the stopped VMs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Administration ==&lt;br /&gt;
To login with the admin account, use the following credentials in the web UI&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Username: admin&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Password: &amp;lt;i&amp;gt;stored in the usual place&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Domain: &amp;lt;i&amp;gt;leave this empty&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is another admin account for the Members domain. This is necessary to create projects in the Members domain which regular members can access. Note that his account has fewer privileges than the root admin account above (it has the DomainAdmin role instead of the RootAdmin role).&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Username: membersadmin&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Password: &amp;lt;i&amp;gt;stored in the usual place&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Domain: Members&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there are two management servers, one on each of biloba and chamomile (chamomile is a hot standby for biloba). If you restart one of them, you should restart the other as well.&lt;br /&gt;
&lt;br /&gt;
=== CLI ===&lt;br /&gt;
CloudStack has a CLI called [https://github.com/apache/cloudstack-cloudmonkey cloudmonkey] which is already set up on biloba. Just run &amp;lt;code&amp;gt;cmk&amp;lt;/code&amp;gt; as root to start it up.&lt;br /&gt;
&lt;br /&gt;
Cloudmonkey is basically a shell for the API (https://cloudstack.apache.org/api/apidocs-4.16/). For example, to list all domains:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listDomains details=min&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Run &amp;lt;code&amp;gt;somecommand -h&amp;lt;/code&amp;gt; to see all parameters for a particular command (or browse the API documentation).&lt;br /&gt;
See https://github.com/apache/cloudstack-cloudmonkey for more details.&lt;br /&gt;
&lt;br /&gt;
== Building packages ==&lt;br /&gt;
While CloudStack does provide .deb packages for Ubuntu, unfortunately these don&#039;t work on Debian (the &#039;qemu-kvm&#039; dependency is a virtual package on Debian, but not on Ubuntu). So we&#039;re going to build our own packages instead.&lt;br /&gt;
&lt;br /&gt;
We&#039;re going to perform the build in a Podman container to avoid polluting the host machine with unnecessary packages. There&#039;s a container called cloudstack-build on biloba which you can re-use. If you create a new container, make sure to use the same Podman image as the release for which you&#039;re building (e.g. &#039;debian:bullseye&#039;).&lt;br /&gt;
&lt;br /&gt;
The instructions below are adapted from http://docs.cloudstack.apache.org/en/latest/installguide/building_from_source.html&lt;br /&gt;
&lt;br /&gt;
Inside the container, install the dependencies:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apt install maven openjdk-11-jdk libws-commons-util-java libcommons-codec-java libcommons-httpclient-java liblog4j1.2-java genisoimage devscripts debhelper python3-setuptools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Install Node.js 12 as well (Debian bullseye&#039;s version happens to be 12):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apt install nodejs npm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Build the node-sass module (see [https://github.com/sass/node-sass/issues/1579 this issue] to see why this is necessary):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ui &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm rebuild node-sass &amp;amp;&amp;amp; cd ..&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The python3-mysql.connector package is not available in bullseye, so we&#039;re going to download and install it from the sid release:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -LOJ http://ftp.ca.debian.org/debian/pool/main/m/mysql-connector-python/python3-mysql.connector_8.0.15-2_all.deb&lt;br /&gt;
apt install ./python3-mysql.connector_8.0.15-2_all.deb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Download the CloudStack source code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -LOJ http://mirror.csclub.uwaterloo.ca/apache/cloudstack/releases/4.16.0.0/apache-cloudstack-4.16.0.0-src.tar.bz2&lt;br /&gt;
tar -jxvf apache-cloudstack-4.16.0.0-src.tar.bz2&lt;br /&gt;
cd apache-cloudstack-4.16.0.0-src&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Download the Maven dependencies:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mvn -P deps&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now open debian/control and perform the following changes:&lt;br /&gt;
&lt;br /&gt;
* Replace &#039;qemu-kvm (&amp;gt;=2.5)&#039; with &#039;qemu-system-x86 (&amp;gt;= 1:5.2)&#039; in the dependencies of cloudstack-agent&lt;br /&gt;
* Remove dh-systemd as a build dependency of cloudstack (it&#039;s included in debhelper)&lt;br /&gt;
&lt;br /&gt;
Now open debian/rules and add the following flags to the &amp;lt;code&amp;gt;mvn&amp;lt;/code&amp;gt; command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-Dmaven.test.skip=true -Dclean.skip=true -Dcheckstyle.skip&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now open debian/changelog and change &#039;unstable&#039; to &#039;bullseye&#039;.&lt;br /&gt;
&lt;br /&gt;
As of this writing, there is a [https://gitlab.com/libvirt/libvirt/-/issues/161 bug in libvirt] which prevents VMs with more than 4GB of RAM from being created on hosts with cgroups2. Until that issue is fixed, we&#039;re going to need to modify the source code. Since we&#039;re already building a custom CloudStack package, it&#039;s easier to patch CloudStack than to patch libvirt, so paste something like the following into debian/patches/fix-cgroups2-cpu-weight.patch:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Description: Workaround for libvirt trying to write a value to the cgroups v2&lt;br /&gt;
  cpu.weight controller which is greater than the maximum (10000). The&lt;br /&gt;
  libvirt developers are currently discussing a solution.&lt;br /&gt;
Forwarded: not-needed&lt;br /&gt;
Origin: upstream, https://gitlab.com/libvirt/libvirt/-/issues/161&lt;br /&gt;
Author: Max Erenberg &amp;lt;merenber@csclub.uwaterloo.ca&amp;gt;&lt;br /&gt;
Last-Update: 2021-12-03&lt;br /&gt;
Index: apache-cloudstack-4.16.0.0-src/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java&lt;br /&gt;
===================================================================&lt;br /&gt;
--- apache-cloudstack-4.16.0.0-src.orig/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java&lt;br /&gt;
+++ apache-cloudstack-4.16.0.0-src/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java&lt;br /&gt;
@@ -1483,6 +1483,10 @@ public class LibvirtVMDef {&lt;br /&gt;
         static final int MAX_PERIOD = 1000000;&lt;br /&gt;
 &lt;br /&gt;
         public void setShares(int shares) {&lt;br /&gt;
+           // Clamp the value to the cgroups v2 cpu.weight maximum until&lt;br /&gt;
+           // upstream libvirt gets fixed:&lt;br /&gt;
+           // https://gitlab.com/libvirt/libvirt/-/issues/161&lt;br /&gt;
+           shares = Math.min(shares, 10000);&lt;br /&gt;
             _shares = shares;&lt;br /&gt;
         }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
I think you have to manually modify that LibvirtVMDef.java file to incorporate those changes (I could be wrong on this, but that&#039;s how I did it).&lt;br /&gt;
&lt;br /&gt;
Then paste the following into debian/patches/00list:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fix-cgroup2-cpu-weight&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, import your GPG key into the container (make sure to delete it afterwards!), and build the packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
debuild -k&amp;lt;YOUR_GPG_KEY_ID&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There should already be a .dupload.conf in the /root directory in the cloudstack-build container; if you need need another copy, ask a syscom member. Open /root/.ssh/config and change the User parameter to your username. Finally, go to /root and upload the packages to potassium-benzoate (replace the version number):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dupload cloudstack_4.16.0.0+1_amd64.changes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Incompatibility with Debian 12 packages ==&lt;br /&gt;
After upgrading ginkgo to bookworm, we discovered that libvirt 8+ was incompatible with CloudStack 4.16.0.0. See https://www.shapeblue.com/advisory-on-libvirt-8-compatibility-issues-with-cloudstack/ for details. So we built new packages from the 4.16.1.0 branch of ShapeBlue&#039;s GitHub repository. For some reason the cloudstack-management process failed with some errors from SLF4J, so we needed to download some JARs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget -O /usr/share/cloudstack-management/lib/log4j-1.2.17.jar https://repo1.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar &lt;br /&gt;
wget -O /usr/share/cloudstack-management/lib/slf4j-log4j12-1.6.6.jar https://repo1.maven.org/maven2/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See https://stackoverflow.com/a/70528383 for details.&lt;br /&gt;
&lt;br /&gt;
We also encountered some kind of Java 11 -&amp;gt; 17 incompatibility issue, so following parameters were added to the JAVA_OPTS variable in /etc/default/cloudstack-management:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--add-opens java.base/java.lang=ALL-UNNAMED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See https://stackoverflow.com/a/41265267 for details. Note that this file is NOT a shell script so you cannot use variable interpolation. You must modify the value of JAVA_OPTS directly.&lt;br /&gt;
&lt;br /&gt;
== Database setup ==&lt;br /&gt;
We are using master-master replication between two MariaDB instances on biloba and chamomile. See [https://mariadb.com/kb/en/setting-up-replication/ here] and [https://tunnelix.com/simple-master-master-replication-on-mariadb/ here] for instructions on how to set this up.&lt;br /&gt;
&lt;br /&gt;
To avoid split-brain syndrome, mariadb.cloud.csclub.uwaterloo.ca points to a virtual IP shared by biloba and chamomile via keepalived. This means that only one host is actually handling requests at any moment; the other is a hot standby.&lt;br /&gt;
&lt;br /&gt;
Also add the following parameters to /etc/mysql/my.cnf on the hosts running MariaDB:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[mysqld]&lt;br /&gt;
innodb_rollback_on_timeout=1&lt;br /&gt;
innodb_lock_wait_timeout=600&lt;br /&gt;
max_connections=350&lt;br /&gt;
log-bin=mysql-bin&lt;br /&gt;
binlog-format = &#039;ROW&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also comment out (or remove) the following line in /etc/mysql/mariadb.conf.d/50-server.cnf:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bind-address = 127.0.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now restart MariaDB.&lt;br /&gt;
&lt;br /&gt;
== Management server setup ==&lt;br /&gt;
Install the management server from our Debian repository:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apt install cloudstack-management&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the database scripts:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cloudstack-setup-databases cloud:password@localhost --deploy-as=root&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
(Replace &#039;password&#039; by a strong password.)&lt;br /&gt;
&lt;br /&gt;
Open /etc/cloudstack/management/db.properties and replace all instances of &#039;localhost&#039; by &#039;mariadb.cloud.csclub.uwaterloo.ca&#039;.&lt;br /&gt;
&lt;br /&gt;
Open /etc/cloudstack/management/server.properties and set &#039;bind-interface&#039; to 127.0.0.1 (CloudStack is being reverse proxied behind NGINX).&lt;br /&gt;
&lt;br /&gt;
Run some more scripts:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cloudstack-setup-management&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mount the cloudstack-secondary CephFS volume at /mnt/cloudstack-secondary:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /mnt/cloudstack-secondary&lt;br /&gt;
mount -t nfs4 -o port=2049 ceph-nfs.cloud.csclub.uwaterloo.ca:/cloudstack-secondary /mnt/cloudstack-secondary&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now download the management VM template:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt -m /mnt/cloudstack-secondary/ -u https://download.cloudstack.org/systemvm/4.16/systemvmtemplate-4.16.0-kvm.qcow2.bz2 -h kvm -F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The management server will run on port 8080 by default, so reverse proxy it from NGINX:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
location / {&lt;br /&gt;
  proxy_pass http://localhost:8080;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compute node setup ==&lt;br /&gt;
Install packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apt install cloudstack-agent libvirt-daemon-driver-storage-rbd qemu-block-extra&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Create a new user for CloudStack:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
useradd -s /bin/bash -d /nonexistent -M cloudstack&lt;br /&gt;
# set the password&lt;br /&gt;
passwd cloudstack&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add the following to /etc/sudoers:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cloudstack ALL=(ALL) NOPASSWD:ALL     &lt;br /&gt;
Defaults:cloudstack !requiretty&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
(There is a way to restrict this, but I was never able to get it to work.)&lt;br /&gt;
&lt;br /&gt;
=== Network setup ===&lt;br /&gt;
The /etc/network/interfaces file should look something like this (taking ginkgo as an example):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
auto enp3s0f0&lt;br /&gt;
iface enp3s0f0 inet manual&lt;br /&gt;
&lt;br /&gt;
auto ens1f0np0&lt;br /&gt;
iface ens1f0np0 inet manual&lt;br /&gt;
&lt;br /&gt;
# csc-cloud management&lt;br /&gt;
auto enp3s0f0.529&lt;br /&gt;
iface enp3s0f0.529 inet manual&lt;br /&gt;
&lt;br /&gt;
auto br529&lt;br /&gt;
iface br529 inet static&lt;br /&gt;
    bridge_ports enp3s0f0.529&lt;br /&gt;
    address 172.19.168.22/27&lt;br /&gt;
iface br529 inet6 static&lt;br /&gt;
    bridge_ports enp3s0f0.529&lt;br /&gt;
    address fd74:6b6a:8eca:4902::22/64&lt;br /&gt;
&lt;br /&gt;
# csc-cloud provider&lt;br /&gt;
auto ens1f0np0.425&lt;br /&gt;
iface ens1f0np0.425 inet manual&lt;br /&gt;
&lt;br /&gt;
auto br425&lt;br /&gt;
iface br425 inet manual&lt;br /&gt;
    bridge_ports ens1f0np0.425&lt;br /&gt;
&lt;br /&gt;
# csc server network&lt;br /&gt;
auto ens1f0np0.134&lt;br /&gt;
iface ens1f0np0.134 inet manual&lt;br /&gt;
&lt;br /&gt;
auto br134&lt;br /&gt;
iface br134 inet static&lt;br /&gt;
    bridge_ports ens1f0np0.134&lt;br /&gt;
    address 129.97.134.148/24&lt;br /&gt;
    gateway 129.97.134.1&lt;br /&gt;
iface br134 inet6 static&lt;br /&gt;
    bridge_ports ens1f0np0.134&lt;br /&gt;
    address 2620:101:f000:4901:c5c::148/64&lt;br /&gt;
    gateway 2620:101:f000:4901::1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add/modify the following lines to /etc/cloudstack/agent.properties:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private.network.device=br529&lt;br /&gt;
guest.network.device=br425&lt;br /&gt;
public.network.device=br425&lt;br /&gt;
host=172.19.168.23,172.19.168.24@static&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== libvirtd setup ===&lt;br /&gt;
Add/modify the following lines in /etc/libvirt/libvirtd.conf:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listen_tls = 0&lt;br /&gt;
listen_tcp = 1&lt;br /&gt;
tcp_port = &amp;quot;16509&amp;quot;&lt;br /&gt;
auth_tcp = &amp;quot;none&amp;quot;&lt;br /&gt;
mdns_adv = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Uncomment the following line in /etc/default/libvirtd:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LIBVIRTD_ARGS=&amp;quot;--listen&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure the following lines are present in /etc/libvirt/qemu.conf:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
security_driver=&amp;quot;none&amp;quot;&lt;br /&gt;
user=&amp;quot;root&amp;quot;&lt;br /&gt;
group=&amp;quot;root&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl mask libvirtd.socket&lt;br /&gt;
systemctl mask libvirtd-ro.socket&lt;br /&gt;
systemctl mask libvirtd-admin.socket&lt;br /&gt;
systemctl restart libvirtd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Management server setup (cont&#039;d) ==&lt;br /&gt;
Now start the cloudstack-management systemd service and visit the web UI (https://cloud.csclub.uwaterloo.ca). The login credentials are &#039;admin&#039; for both the username and password. Start the setup walkthrough (you will be prompted to change the password). Make sure to choose Basic Networking.&lt;br /&gt;
&lt;br /&gt;
The walkthrough is almost certainly going to fail (at least, it did for me). Don&#039;t panic when this happens; just abort the walkthrough, and set up everything else manually. Once primary and secondary storage have been setup, and at least one host has been added, enable the Pod, Cluster and Zone (there should only be one of each).&lt;br /&gt;
&lt;br /&gt;
=== Primary Storage ===&lt;br /&gt;
* Type: RBD&lt;br /&gt;
* IP address: ceph-mon.cloud.csclub.uwaterloo.ca&lt;br /&gt;
* Scope: zone&lt;br /&gt;
* Get the credentials which you created in [[Ceph#CloudStack_Primary_Storage]]&lt;br /&gt;
&lt;br /&gt;
=== Secondary Storage ===&lt;br /&gt;
* Type: NFS&lt;br /&gt;
* Host: ceph-nfs.cloud.csclub.uwaterloo.ca:2049&lt;br /&gt;
* Path: /cloudstack-secondary&lt;br /&gt;
&lt;br /&gt;
=== Global settings ===&lt;br /&gt;
Some global settings which you&#039;ll need to set from the web UI:&lt;br /&gt;
&lt;br /&gt;
* ca.plugin.root.auth.strictness: false (this always caused issues for me, so I just disabled it)&lt;br /&gt;
* host: 172.19.168.23,172.19.168.24  (the VLAN 529 addresses of biloba and chamomile)&lt;br /&gt;
&lt;br /&gt;
=== Adding a host ===&lt;br /&gt;
This is an extremely painful process which I am almost certainly doing wrong. It usually takes me 7-8 attempts to add a single host (that&#039;s not an exaggeration). This is what it looks like:&lt;br /&gt;
&lt;br /&gt;
* Stop cloudstack-agent service&lt;br /&gt;
* Configure /etc/cloudstack-agent/agent.properties&lt;br /&gt;
* Add a host from the CloudStack UI&lt;br /&gt;
* Start cloudstack-agent.service&lt;br /&gt;
&lt;br /&gt;
The reason why this takes several attempts is because cloudstack-agent actually &amp;lt;i&amp;gt;overwrites&amp;lt;/i&amp;gt; your agent.properties file. If/when you notice that this happens, restart the whole process again.&lt;br /&gt;
&lt;br /&gt;
=== Accessing the System VMs ===&lt;br /&gt;
If you need to SSH into one of the System VMs, get its link-local address from the web UI, and run e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh -i /var/lib/cloudstack/management/.ssh/id_rsa -p 3922 root@169.254.232.179&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Some more global settings ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow.user.expunge.recover.vm = true&lt;br /&gt;
allow.user.view.destroyed.vm = true&lt;br /&gt;
expunge.delay = 1&lt;br /&gt;
expunge.interval = 1&lt;br /&gt;
network.securitygroups.defaultadding = false&lt;br /&gt;
allow.public.user.templates = false&lt;br /&gt;
vm.network.throttling.rate = 0&lt;br /&gt;
network.throttling.rate = 0&lt;br /&gt;
cpu.overprovisioning.factor = 4.0&lt;br /&gt;
allow.user.create.projects = false&lt;br /&gt;
max.project.cpus = 8&lt;br /&gt;
max.project.memory = 8192&lt;br /&gt;
max.project.primary.storage = 40&lt;br /&gt;
max.projet.secondary.storage = 20&lt;br /&gt;
max.account.cpus = 8&lt;br /&gt;
max.account.memory = 8192&lt;br /&gt;
max.account.primary.storage = 40&lt;br /&gt;
max.account.secondary.storage = 20&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOTE&amp;lt;/b&amp;gt;: the &amp;lt;code&amp;gt;cpu.overprovisioning.factor&amp;lt;/code&amp;gt; setting also needs to be set for existing clusters. Go to Infrastructure -&amp;gt; Clusters -&amp;gt; Cluster1 -&amp;gt; Settings and set it accordingly.&lt;br /&gt;
&lt;br /&gt;
=== Firewall ===&lt;br /&gt;
Since we disabled certificate validation from the clients, we&#039;re going to use some iptables-fu on all of the CloudStack hosts (to make our lives easier, we&#039;re going to use the same rules on the management and agent servers):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
iptables -N CLOUDSTACK-SERVICES&lt;br /&gt;
iptables -A INPUT -j CLOUDSTACK-SERVICES&lt;br /&gt;
iptables -A CLOUDSTACK-SERVICES -i lo -j RETURN&lt;br /&gt;
iptables -A CLOUDSTACK-SERVICES -s 172.19.168.0/27 -j RETURN&lt;br /&gt;
iptables -A CLOUDSTACK-SERVICES -p tcp -m multiport --dports 16509,16514,45335,41047,8250 -j REJECT&lt;br /&gt;
iptables-save &amp;gt; /etc/iptables/rules.v4&lt;br /&gt;
&lt;br /&gt;
ip6tables -N CLOUDSTACK-SERVICES&lt;br /&gt;
ip6tables -A INPUT -j CLOUDSTACK-SERVICES&lt;br /&gt;
ip6tables -A CLOUDSTACK-SERVICES -i lo -j RETURN&lt;br /&gt;
ip6tables -A CLOUDSTACK-SERVICES -s fd74:6b6a:8eca:4902::/64 -j RETURN&lt;br /&gt;
ip6tables -A CLOUDSTACK-SERVICES -p tcp -m multiport --dports 16509,16514,45335,41047,8250 -j REJECT&lt;br /&gt;
ip6tables-save &amp;gt; /etc/iptables/rules.v6&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LDAP authentication ===&lt;br /&gt;
Go to Global Settings in the UI, type &#039;ldap&#039; in the search bar, and configure the parameters as needed. Make sure the mail attribute is set to &#039;mailLocalAddress&#039;.&lt;br /&gt;
&lt;br /&gt;
Create a new domain called &#039;Members&#039;. Then go to &#039;LDAP Configuration&#039;, click the &#039;Configure LDAP +&#039; button, and add a new LDAP config linked to the domain you just created.&lt;br /&gt;
&lt;br /&gt;
[[ceo]] handles the creation of CloudStack accounts, so create an API key + secret token and add it to /etc/csc/ceod.ini on biloba.&lt;br /&gt;
&lt;br /&gt;
=== Templates ===&lt;br /&gt;
This deserves an entire page of its own - see [[CloudStack Templates]].&lt;br /&gt;
&lt;br /&gt;
=== Kubernetes ===&lt;br /&gt;
This deserves an entire page of its own - see [[Kubernetes]].&lt;br /&gt;
&lt;br /&gt;
== Upgrading CloudStack ==&lt;br /&gt;
Please be &amp;lt;b&amp;gt;extremely&amp;lt;/b&amp;gt; careful if you decide to upgrade CloudStack. The last time I tried to perform an upgrade (from 4.15 to 4.16), the agents refused to connect to the management servers (or maybe it was the other way around?), and I ended up having to &amp;lt;b&amp;gt;wipe the entire CloudStack installation clean and start again from scratch&amp;lt;/b&amp;gt;. Therefore it is fair to say that nobody has ever managed to successfully upgrade CloudStack on our machines. Do this at your own risk.&lt;br /&gt;
&lt;br /&gt;
If you decide to perform an upgrade, then at the very least, you will need to backup the MariaDB databases (&#039;cloud&#039; and &#039;cloud_usage&#039;), as well as the /etc/cloudstack and /var/lib/cloudstack folders on each of biloba, chamomile and ginkgo. Also, good luck.&lt;br /&gt;
&lt;br /&gt;
== Siracha Crash Out Notes ==&lt;br /&gt;
If you ever find your self in the unfourtunate position of needing to recover from a drive failure. It&#039;s JOEVER BRO TRUST ME. &lt;br /&gt;
&lt;br /&gt;
Anyways this is what I&#039;ve learned from the pits of hell&lt;br /&gt;
&lt;br /&gt;
# Our nginx config is funny, and it redirects 9987 → gunicorn → ceod instance running on server&lt;br /&gt;
## If the drive dies, ask someone with a backup for just a zip file, it&#039;s not possible to recover. Trust me&lt;br /&gt;
# you need to reload both nginx &amp;amp; cloudstack to get it running&lt;br /&gt;
# You need the crt to get it working (stored under `/etc/csc/k8s` (I think)&lt;br /&gt;
&lt;br /&gt;
== Crash Out Notes Cont. ==&lt;br /&gt;
The user console on CloudStack was not working.&lt;br /&gt;
&lt;br /&gt;
In Chamomile &amp;lt;code&amp;gt;/etc/nginx/sites-enabled&amp;lt;/code&amp;gt;, you can see a list of all user websites that are enabled. There&#039;s a file entitled &amp;lt;code&amp;gt;consoleproxy.cloud.csclub.uwaterloo.ca&amp;lt;/code&amp;gt; in which you will find that the console proxy is being hosted on the VM with IP &amp;lt;code&amp;gt;172.19.134.59&amp;lt;/code&amp;gt; on CloudStack.&lt;br /&gt;
&lt;br /&gt;
Run the following command whilst in Chamomile to access the console proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo ssh -i /var/lib/cloudstack/management/.ssh/id_rsa -p 3922 169.254.35.150&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More information on troubleshooting the console and console proxy can be found [https://cwiki.apache.org/confluence/display/CLOUDSTACK/View+Console+and+Console+Proxy+Troubleshooting here.]&lt;/div&gt;</summary>
		<author><name>K57chan</name></author>
	</entry>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5381</id>
		<title>Web Hosting</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5381"/>
		<updated>2025-06-30T17:02:08Z</updated>

		<summary type="html">&lt;p&gt;K57chan: /* Fighting AI scrappers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The CSC offers web hosting for [[Club Hosting|clubs]] and [http://csclub.uwaterloo.ca/about/ our members] in accordance with our [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. This is a quick guide for the kinds of hosting we offer on our webserver, &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;, also known as [[Machine List#caffeine|caffeine]].&lt;br /&gt;
&lt;br /&gt;
We run an Apache httpd webserver and we offer you the use of a [[MySQL|MySQL database]].&lt;br /&gt;
&lt;br /&gt;
== What can I host on my website? ==&lt;br /&gt;
&lt;br /&gt;
Web hosting is provided in accordance with the CSC [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. As a reminder, you are &#039;&#039;&#039;not permitted&#039;&#039;&#039; to host any of the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ads.&#039;&#039;&#039; Advertisements are not permitted because using our machines for commercial purposes is forbidden by university policy.&lt;br /&gt;
* &#039;&#039;&#039;Your start-up&#039;s website.&#039;&#039;&#039; Again, commercial use of our hosting is not permitted.&lt;br /&gt;
* &#039;&#039;&#039;Unauthorized copyrighted materials.&#039;&#039;&#039; Violating the law is a violation of our Machine Usage Agreement.&lt;br /&gt;
&lt;br /&gt;
Please note that &#039;&#039;&#039;this is not an exhaustive list. Websites may be taken down &#039;&#039;without notice&#039;&#039;&#039;&#039;&#039; at the discretion of the Systems Committee. (We will always let you know that we took your site down, but if it is breaking our shared environment, we can&#039;t provide an advance warning.)&lt;br /&gt;
&lt;br /&gt;
Some great examples of things members host on our webserver:&lt;br /&gt;
&lt;br /&gt;
* Academic projects!&lt;br /&gt;
* A personal website or blog!&lt;br /&gt;
* [[Club Hosting|Club websites!]]&lt;br /&gt;
&lt;br /&gt;
== How do I make a website? ==&lt;br /&gt;
&lt;br /&gt;
If you just want to show some static content (e.g. blog posts, club information, technical articles), then we recommend that you use a static site generator (SSG). Static sites are faster, simpler and more secure than CMSs like WordPress (dynamic and written in PHP) for small sites. We routinely disable WordPress sites that are more than a few weeks out of date (or if a critical security flaw is disclosed).&lt;br /&gt;
&lt;br /&gt;
Here are some SSGs which require little to no coding experience, and also have a great selection of themes to choose from:&lt;br /&gt;
&lt;br /&gt;
* [https://jekyllrb.com/ Jekyll] (accepts Markdown, Liquid and HTML)&lt;br /&gt;
* [https://gohugo.io/ Hugo] (accepts a wide variety of formats, including Markdown and JSON)&lt;br /&gt;
* [https://hexo.io/ Hexo] (accepts Markdown and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.11ty.dev/ Eleventy] (accepts Markdown, Liquid, HTML, and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.getzola.org/ Zola] (accepts Markdown and Tera)&lt;br /&gt;
* [https://blog.getpelican.com/ Pelican] (accepts Markdown, reStructuredText and Jinja2)&lt;br /&gt;
&lt;br /&gt;
[https://astro.build/ Astro] is an excellent static site builder which integrates with a wide variety of JS-based frameworks (including React, Vue, Svelte and Solid), but requires a bit more coding experience.&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with React.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nextjs.org/ Next.js]&lt;br /&gt;
* [https://www.gatsbyjs.com/ Gatsby.js]&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with Vue.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nuxtjs.org/ Nuxt.js]&lt;br /&gt;
* [https://vuepress.vuejs.org/ Vuepress]&lt;br /&gt;
* [https://vitepress.vuejs.org/ Vitepress]&lt;br /&gt;
* [https://gridsome.org/ Gridsome]&lt;br /&gt;
&lt;br /&gt;
[https://jamstack.org/generators/ Here] is an awesome list of other generators to explore, if you are interested.&lt;br /&gt;
&lt;br /&gt;
=== Transferring your files to the CSC servers ===&lt;br /&gt;
If you just need to transfer a single file, then the easiest option is to use the &amp;lt;code&amp;gt;scp&amp;lt;/code&amp;gt; command (which is available on all major operating systems), e.g.&lt;br /&gt;
&lt;br /&gt;
  scp /path/to/your/file your_username@corn-syrup.csclub.uwaterloo.ca:~/&lt;br /&gt;
&lt;br /&gt;
This will copy /path/to/your/file from your local PC to your CSC home directory (we use NFS, so you can access it from any of the general-use machines).&lt;br /&gt;
&lt;br /&gt;
However, we strongly recommend setting up a git repository in your home directory instead.&lt;br /&gt;
&lt;br /&gt;
=== Setting up a git repository ===&lt;br /&gt;
All of the files in the &amp;lt;code&amp;gt;www&amp;lt;/code&amp;gt; directory in your home directory are accessible from csclub.uwaterloo.ca/~your_username. If everything is set up right, this can provide a GitHub Pages-like experience.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Create a &amp;quot;bare&amp;quot; git repository in your home directory (on the CSC machines). You will git push/pull from this directory.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Switch to the Unix user for your club, and use the &amp;lt;code&amp;gt;--shared&amp;lt;/code&amp;gt; option to automatically add group write permissions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
become_club myclub&lt;br /&gt;
cd ~&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare --shared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Create a git post-receive hook which will automatically deploy your website whenever you git push. Paste the following script into hooks/post-receive (in the bare repo you created earlier). You may wish to customize it a bit first.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
# Uncomment this to echo the commands as they are executed&lt;br /&gt;
#set -x&lt;br /&gt;
shopt -s dotglob&lt;br /&gt;
# FOR CLUB REPS ONLY: set the following variable to e.g. /users/myclub/www&lt;br /&gt;
DEPLOYMENT_DIR=~/www&lt;br /&gt;
&lt;br /&gt;
while read oldrev newrev refname; do&lt;br /&gt;
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)&lt;br /&gt;
    # Only the master branch will be deployed&lt;br /&gt;
    if [ &amp;quot;$branch&amp;quot; != master ]; then&lt;br /&gt;
        continue&lt;br /&gt;
    fi&lt;br /&gt;
    rm -rf $DEPLOYMENT_DIR/*&lt;br /&gt;
    git --work-tree=$DEPLOYMENT_DIR checkout -f $branch&lt;br /&gt;
    # FOR CLUB REPS ONLY: uncomment the following lines and replace &#039;myclub&#039;&lt;br /&gt;
    # with the Unix group name of your club&lt;br /&gt;
    #chgrp -R myclub $DEPLOYMENT_DIR&lt;br /&gt;
    #chmod -R g+w $DEPLOYMENT_DIR&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
(The script was adapted from [https://peteris.rocks/blog/deploy-your-website-with-git/ here].)&lt;br /&gt;
&lt;br /&gt;
Make the script executable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x hooks/post-receive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;For club reps&amp;lt;/b&amp;gt;: Make sure the www directory is group-writable. Switch to the Unix user of your club and run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+w ~/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have not done so already, add your public SSH key to your ~/.ssh/authorized_keys file (on the CSC machines). See [https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key here] for a tutorial.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
On your local computer, add [[Machine_List|any CSC machine]] as a remote of your git repo.&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Just use the directory of your git repo, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Use the full path of the repo in your club user&#039;s home directory, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:/users/myclub/myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Now you can just &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; normally after a commit, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git push csc master&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And the files should show up automatically in your www folder (or your club&#039;s www folder, if you are a club rep).&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have any files in your repo which you don&#039;t want to be served from your website, use a [https://httpd.apache.org/docs/2.4/howto/htaccess.html .htaccess file] in your www folder (make sure this is committed to the git repo). For example, to deny access to the folder named src (in your www folder), you could use the following snippet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
RewriteRule &amp;quot;^src(/.*)?$&amp;quot; - [F,L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See [https://httpd.apache.org/docs/2.4/mod/core.html the Apache documentation] for more details.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need help, email &amp;lt;tt&amp;gt;syscom@csclub.uwaterloo.ca[mailto:syscom@csclub.uwaterloo.ca]&amp;lt;/tt&amp;gt; or come to the CS Club office on the MC 3rd floor across from the Mathsoc CnD.&lt;br /&gt;
&lt;br /&gt;
== DNS and Your Domain Name ==&lt;br /&gt;
&lt;br /&gt;
You can serve files without any additional configuration by placing them in your &amp;lt;tt&amp;gt;www&amp;lt;/tt&amp;gt; directory and accessing them at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;userid&amp;lt;/tt&amp;gt; is your CSC user ID. However, many of our members and clubs prefer to use a custom domain name.&lt;br /&gt;
&lt;br /&gt;
Note that this means you &#039;&#039;do not&#039;&#039; have to register a domain name to be able to use our services. You can just put a website at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== uwaterloo.ca domain Names ===&lt;br /&gt;
&lt;br /&gt;
If you represent a UWaterloo organization, you may be eligible for a custom &amp;lt;tt&amp;gt;uwaterloo.ca&amp;lt;/tt&amp;gt; domain name, such as &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;. We can request this on your behalf.&lt;br /&gt;
&lt;br /&gt;
In order to do so, we must have verified that the organization is a legitimate UWaterloo-affiliated group, and that you, the representative, are authorized to request a domain name on their behalf. This all takes place when you request [[Club Hosting|club hosting]] with the Computer Science Club.&lt;br /&gt;
&lt;br /&gt;
Once you register as a club representative of your particular organization, you can send an email from your official club account to syscom@csclub.uwaterloo.ca to request the domain &amp;lt;tt&amp;gt;yourdomain.uwaterloo.ca&amp;lt;/tt&amp;gt;. Assuming it is available, we will file a ticket and request the domain in your name.&lt;br /&gt;
&lt;br /&gt;
=== Your personal domain name ===&lt;br /&gt;
&lt;br /&gt;
These virtual hosts must be approved by the Executive and Systems Committee. If interested, send syscom@csclub.uwaterloo.ca an email. If your request is approved, the Systems Committee will direct you to create a CNAME record for your domain and point it at &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you are interested in receiving mail or having other records on your domain, the apex of your domain cannot be a CNAME. If this is the case, then your domain should contain an &amp;quot;A&amp;quot; record of &amp;lt;tt&amp;gt;129.97.134.17&amp;lt;/tt&amp;gt; and a (optional, but recommended) &amp;quot;AAAA&amp;quot; record of &amp;lt;tt&amp;gt;2620:101:f000:4901:c5c::caff:e12e&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you want TLS on your personal domain, mention this in your email to syscom (syscom: see [[SSL#letsencrypt]]).&lt;br /&gt;
&lt;br /&gt;
== Static Sites ==&lt;br /&gt;
&lt;br /&gt;
You can place all your static content into your web directory, &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you have been approved for a virtual host, you can access this content using your personal domain once the Systems Committee makes the appropriate configuration changes. Here is an example configuration file:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
  	ServerName foobar.uwaterloo.ca&lt;br /&gt;
  	ServerAlias *.foobar.uwaterloo.ca foobar&lt;br /&gt;
  	ServerAdmin your@email.here.tld&lt;br /&gt;
  &lt;br /&gt;
  	DocumentRoot /users/userid/www/&lt;br /&gt;
  &lt;br /&gt;
  	ErrorLog /var/log/apache2/luser-userid-error.log&lt;br /&gt;
  	CustomLog /var/log/apache2/luser-userid-access.log combined&lt;br /&gt;
  &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dynamic Sites ==&lt;br /&gt;
&lt;br /&gt;
If you require use of a database, we offer you the sole choice of MySQL. See [[MySQL|this guide]] for how to create your database and connect to MySQL.&lt;br /&gt;
&lt;br /&gt;
=== ***NOTICE*** ===&lt;br /&gt;
&lt;br /&gt;
  We &#039;&#039;&#039;STRONGLY&#039;&#039;&#039; discourage the use of content management systems such as&lt;br /&gt;
  WordPress. These packages are notorious for the number of security&lt;br /&gt;
  vulnerabilities they contain and pose a threat to our systems if they are not&lt;br /&gt;
  kept up to date. The Systems Committee &#039;&#039;&#039;WILL,&#039;&#039;&#039; at its discretion, disable&lt;br /&gt;
  any website using a package such as WordPress that is not updated to the latest&lt;br /&gt;
  version or that is found to contain exploitable security flaws. In such a case,&lt;br /&gt;
  the member or club serving that site will be notified of the termination; the&lt;br /&gt;
  site will not be re-enabled until the issues are addressed.&lt;br /&gt;
&lt;br /&gt;
When pages are parked, access to them is restricted to on-campus IPs, so you can still fix your page, but anyone off-campus will not be able to access it, and will be shown this page instead: [https://csclub.uwaterloo.ca/~sysadmin/insecure/ https://csclub.uwaterloo.ca/~sysadmin/insecure/].&lt;br /&gt;
&lt;br /&gt;
=== Using PHP ===&lt;br /&gt;
&lt;br /&gt;
Because we use Apache, it&#039;s as simple as placing your &amp;lt;tt&amp;gt;index.php&amp;lt;/tt&amp;gt; file in your &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;. That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
You can even include rewrite rules in an &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; file in your web directory.&lt;br /&gt;
&lt;br /&gt;
=== Reverse Proxy (Python, Ruby, Perl, etc.) ===&lt;br /&gt;
&lt;br /&gt;
(In progress... Cliff Notes below)&lt;br /&gt;
&lt;br /&gt;
If computationally expensive, please run the server on a general-use server and proxy to Caffeine.&lt;br /&gt;
&lt;br /&gt;
If Python, (1) use a [http://docs.python-guide.org/en/latest/dev/virtualenvs/ virtual environment] (2) host your app (within the virtualenv) with [http://gunicorn.org/ Gunicorn] on a high port (but campus firewalled, i.e. NOT Ports 28000-28500).&lt;br /&gt;
&lt;br /&gt;
If Ruby (Note, I&#039;ve never used Ruby so take this with a grain of salt), use [http://unicorn.bogomips.org/ Unicorn] in the same way.&lt;br /&gt;
&lt;br /&gt;
==== .htaccess Config ====&lt;br /&gt;
&lt;br /&gt;
Put the following in the appropriate .htaccess file (e.g. if you were running your app at ~ctdalek/python-app, put the .htaccess in ~ctdalek/www/python-app alongside the static files). Replace HOST with localhost if running on Caffeine or the hostname if running elsewhere; replace port with your chosen port number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
&lt;br /&gt;
# If you want websockets, uncomment this:&lt;br /&gt;
#RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]&lt;br /&gt;
#RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]&lt;br /&gt;
#RewriteRule .* ws://HOST:RANDOM_PORT%{REQUEST_URI} [L,P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;index.html&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/&amp;quot; [P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;^(.*)$&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/$1&amp;quot; [P]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Requiring Authentication ==&lt;br /&gt;
&amp;lt;b&amp;gt;**UPDATE**&amp;lt;/b&amp;gt;: CAS is deprecated; the instructions below are left for historical purposes only. The University of Waterloo now uses [[ADFS]] for web authentication. Unfortunately the Apache module which we use to integrate with ADFS (mod_auth_mellon) cannot be used from .htaccess files, which means that regular members cannot use this. ([https://github.com/latchset/mod_auth_mellon/issues/82 Here] is the relevant GitHub issue; as of this writing, it is still open.) If you require UW authentication for your website, please send an email to syscom and we will configure Apache for you.&lt;br /&gt;
&lt;br /&gt;
=== CAS (no longer works) ===&lt;br /&gt;
You can require users to authenticate through the University&#039;s Central Authentication System (CAS) by adding the following contents to your .htaccess configuration file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AuthType CAS&lt;br /&gt;
Require valid-user&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can replace &amp;lt;pre&amp;gt;Require valid-user&amp;lt;/pre&amp;gt; with &amp;lt;pre&amp;gt;Require user ctdalek&amp;lt;/pre&amp;gt; to restrict to specific users. See https://doubledoublesecurity.ca/uw/cas/user.html for more information.&lt;br /&gt;
&lt;br /&gt;
== Syscom ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling insecure or infringing sites ===&lt;br /&gt;
&lt;br /&gt;
To disable a webspace that has known security vulnerabilities add the following snippet to `/etc/apache2/conf-available/disable-vuln-site.conf`. This rewrites all accesses of the directory or its children to the given file. Note that our disable page always returns HTTP status code 503 (Service Unavailable).&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory /users/$BADUSER/www&amp;gt;&lt;br /&gt;
     AllowOverride None&lt;br /&gt;
     Redirect 503 /&lt;br /&gt;
     ErrorDocument 503 /~sysadmin/insecure/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For infringing sites:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADUSER/www/infringing-directory&amp;quot;&amp;gt;&lt;br /&gt;
    AllowOverride None&lt;br /&gt;
    Redirect 503 /&lt;br /&gt;
    ErrorDocument 503 /~sysadmin/infringing/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For club domains (e.g. club1.uwaterloo.ca), redirect to the CSC domain instead:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   AllowOverride None&lt;br /&gt;
   RewriteEngine On&lt;br /&gt;
   RewriteRule . &amp;lt;nowiki&amp;gt;https://csclub.uwaterloo.ca/~sysadmin/insecure/index.php&amp;lt;/nowiki&amp;gt; [L,P]&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For WordPress sites specifically, insert a snippet similar to the following into conf-enabled/disable-wordpress.conf:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   Include snippets/disable-wordpress.conf&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Expired Websites ===&lt;br /&gt;
&lt;br /&gt;
There is a cron job running hourly on caffeine which disables expired member&#039;s websites (and re-enables them when they&#039;ve renewed their membership).&lt;br /&gt;
&lt;br /&gt;
The script is here: https://git.csclub.uwaterloo.ca/public/expire-sites&lt;br /&gt;
&lt;br /&gt;
Some highlights:&lt;br /&gt;
&lt;br /&gt;
* The script provides a 1-month grace period (corresponding to the grace period of pam-csc)&lt;br /&gt;
* The expired page returns HTTP status code of 503 (Service Unavailable)&lt;br /&gt;
&lt;br /&gt;
=== Fighting AI scrappers ===&lt;br /&gt;
We use [https://github.com/TecharoHQ/anubis Anubis] to block excess AI scrappers. This sits between Apache2 and the real application to insert a proof-of-work challenge for the browser to solve, before proceeding to provide the actual content.&lt;br /&gt;
&lt;br /&gt;
Since Anubis requires JavaScript, it is only selectively enabled on sites that a) is currently getting excessively scraped and b) need JavaScript already.&lt;br /&gt;
&lt;br /&gt;
Currently, only [[Git Hosting]] is protected.&lt;br /&gt;
&lt;br /&gt;
See &amp;lt;code&amp;gt;caffeine:/etc/anubis&amp;lt;/code&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
Anubis might break services running on the CSC servers (e.g. Renovate Bot). To fix this, simply add the service into the list of Anubis&#039; exceptions (gitea.botPolicies.json). Afterwards, restart Anubis, Apache, and Gitea.&lt;br /&gt;
&lt;br /&gt;
=== Sample Apache config for website with both a custom domain and a UW subdomain ===&lt;br /&gt;
&lt;br /&gt;
 Define ENTITY_NAME pmclub&lt;br /&gt;
 Define CUSTOM_DOMAIN puremath.club&lt;br /&gt;
 Define UW_SUBDOMAIN ${ENTITY_NAME}.uwaterloo.ca&lt;br /&gt;
 Define ADMIN_EMAIL ${ENTITY_NAME}@csclub.uwaterloo.ca&lt;br /&gt;
 Define ENTITY_HOME https://csclub.uwaterloo.ca/~${ENTITY_NAME}&lt;br /&gt;
 &lt;br /&gt;
 Define APACHE_LOG_DIR /var/log/apache2&lt;br /&gt;
 Define ERROR_LOG ${APACHE_LOG_DIR}/${ENTITY_NAME}-error.log&lt;br /&gt;
 Define CUSTOM_LOG &amp;quot;${APACHE_LOG_DIR}/${ENTITY_NAME}-access.log combined&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN} ${UW_SUBDOMAIN} *.${UW_SUBDOMAIN} ${ENTITY_NAME}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	DocumentRoot /users/${ENTITY_NAME}/www&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent /&amp;lt;special page&amp;gt; ${ENTITY_HOME}/&amp;lt;special path&amp;gt;/&amp;lt;special file&amp;gt;&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAlias *.${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;/div&gt;</summary>
		<author><name>K57chan</name></author>
	</entry>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5376</id>
		<title>Web Hosting</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5376"/>
		<updated>2025-06-28T00:08:59Z</updated>

		<summary type="html">&lt;p&gt;K57chan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The CSC offers web hosting for [[Club Hosting|clubs]] and [http://csclub.uwaterloo.ca/about/ our members] in accordance with our [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. This is a quick guide for the kinds of hosting we offer on our webserver, &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;, also known as [[Machine List#caffeine|caffeine]].&lt;br /&gt;
&lt;br /&gt;
We run an Apache httpd webserver and we offer you the use of a [[MySQL|MySQL database]].&lt;br /&gt;
&lt;br /&gt;
== What can I host on my website? ==&lt;br /&gt;
&lt;br /&gt;
Web hosting is provided in accordance with the CSC [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. As a reminder, you are &#039;&#039;&#039;not permitted&#039;&#039;&#039; to host any of the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ads.&#039;&#039;&#039; Advertisements are not permitted because using our machines for commercial purposes is forbidden by university policy.&lt;br /&gt;
* &#039;&#039;&#039;Your start-up&#039;s website.&#039;&#039;&#039; Again, commercial use of our hosting is not permitted.&lt;br /&gt;
* &#039;&#039;&#039;Unauthorized copyrighted materials.&#039;&#039;&#039; Violating the law is a violation of our Machine Usage Agreement.&lt;br /&gt;
&lt;br /&gt;
Please note that &#039;&#039;&#039;this is not an exhaustive list. Websites may be taken down &#039;&#039;without notice&#039;&#039;&#039;&#039;&#039; at the discretion of the Systems Committee. (We will always let you know that we took your site down, but if it is breaking our shared environment, we can&#039;t provide an advance warning.)&lt;br /&gt;
&lt;br /&gt;
Some great examples of things members host on our webserver:&lt;br /&gt;
&lt;br /&gt;
* Academic projects!&lt;br /&gt;
* A personal website or blog!&lt;br /&gt;
* [[Club Hosting|Club websites!]]&lt;br /&gt;
&lt;br /&gt;
== How do I make a website? ==&lt;br /&gt;
&lt;br /&gt;
If you just want to show some static content (e.g. blog posts, club information, technical articles), then we recommend that you use a static site generator (SSG). Static sites are faster, simpler and more secure than CMSs like WordPress (dynamic and written in PHP) for small sites. We routinely disable WordPress sites that are more than a few weeks out of date (or if a critical security flaw is disclosed).&lt;br /&gt;
&lt;br /&gt;
Here are some SSGs which require little to no coding experience, and also have a great selection of themes to choose from:&lt;br /&gt;
&lt;br /&gt;
* [https://jekyllrb.com/ Jekyll] (accepts Markdown, Liquid and HTML)&lt;br /&gt;
* [https://gohugo.io/ Hugo] (accepts a wide variety of formats, including Markdown and JSON)&lt;br /&gt;
* [https://hexo.io/ Hexo] (accepts Markdown and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.11ty.dev/ Eleventy] (accepts Markdown, Liquid, HTML, and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.getzola.org/ Zola] (accepts Markdown and Tera)&lt;br /&gt;
* [https://blog.getpelican.com/ Pelican] (accepts Markdown, reStructuredText and Jinja2)&lt;br /&gt;
&lt;br /&gt;
[https://astro.build/ Astro] is an excellent static site builder which integrates with a wide variety of JS-based frameworks (including React, Vue, Svelte and Solid), but requires a bit more coding experience.&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with React.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nextjs.org/ Next.js]&lt;br /&gt;
* [https://www.gatsbyjs.com/ Gatsby.js]&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with Vue.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nuxtjs.org/ Nuxt.js]&lt;br /&gt;
* [https://vuepress.vuejs.org/ Vuepress]&lt;br /&gt;
* [https://vitepress.vuejs.org/ Vitepress]&lt;br /&gt;
* [https://gridsome.org/ Gridsome]&lt;br /&gt;
&lt;br /&gt;
[https://jamstack.org/generators/ Here] is an awesome list of other generators to explore, if you are interested.&lt;br /&gt;
&lt;br /&gt;
=== Transferring your files to the CSC servers ===&lt;br /&gt;
If you just need to transfer a single file, then the easiest option is to use the &amp;lt;code&amp;gt;scp&amp;lt;/code&amp;gt; command (which is available on all major operating systems), e.g.&lt;br /&gt;
&lt;br /&gt;
  scp /path/to/your/file your_username@corn-syrup.csclub.uwaterloo.ca:~/&lt;br /&gt;
&lt;br /&gt;
This will copy /path/to/your/file from your local PC to your CSC home directory (we use NFS, so you can access it from any of the general-use machines).&lt;br /&gt;
&lt;br /&gt;
However, we strongly recommend setting up a git repository in your home directory instead.&lt;br /&gt;
&lt;br /&gt;
=== Setting up a git repository ===&lt;br /&gt;
All of the files in the &amp;lt;code&amp;gt;www&amp;lt;/code&amp;gt; directory in your home directory are accessible from csclub.uwaterloo.ca/~your_username. If everything is set up right, this can provide a GitHub Pages-like experience.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Create a &amp;quot;bare&amp;quot; git repository in your home directory (on the CSC machines). You will git push/pull from this directory.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Switch to the Unix user for your club, and use the &amp;lt;code&amp;gt;--shared&amp;lt;/code&amp;gt; option to automatically add group write permissions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
become_club myclub&lt;br /&gt;
cd ~&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare --shared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Create a git post-receive hook which will automatically deploy your website whenever you git push. Paste the following script into hooks/post-receive (in the bare repo you created earlier). You may wish to customize it a bit first.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
# Uncomment this to echo the commands as they are executed&lt;br /&gt;
#set -x&lt;br /&gt;
shopt -s dotglob&lt;br /&gt;
# FOR CLUB REPS ONLY: set the following variable to e.g. /users/myclub/www&lt;br /&gt;
DEPLOYMENT_DIR=~/www&lt;br /&gt;
&lt;br /&gt;
while read oldrev newrev refname; do&lt;br /&gt;
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)&lt;br /&gt;
    # Only the master branch will be deployed&lt;br /&gt;
    if [ &amp;quot;$branch&amp;quot; != master ]; then&lt;br /&gt;
        continue&lt;br /&gt;
    fi&lt;br /&gt;
    rm -rf $DEPLOYMENT_DIR/*&lt;br /&gt;
    git --work-tree=$DEPLOYMENT_DIR checkout -f $branch&lt;br /&gt;
    # FOR CLUB REPS ONLY: uncomment the following lines and replace &#039;myclub&#039;&lt;br /&gt;
    # with the Unix group name of your club&lt;br /&gt;
    #chgrp -R myclub $DEPLOYMENT_DIR&lt;br /&gt;
    #chmod -R g+w $DEPLOYMENT_DIR&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
(The script was adapted from [https://peteris.rocks/blog/deploy-your-website-with-git/ here].)&lt;br /&gt;
&lt;br /&gt;
Make the script executable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x hooks/post-receive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;For club reps&amp;lt;/b&amp;gt;: Make sure the www directory is group-writable. Switch to the Unix user of your club and run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+w ~/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have not done so already, add your public SSH key to your ~/.ssh/authorized_keys file (on the CSC machines). See [https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key here] for a tutorial.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
On your local computer, add [[Machine_List|any CSC machine]] as a remote of your git repo.&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Just use the directory of your git repo, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Use the full path of the repo in your club user&#039;s home directory, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:/users/myclub/myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Now you can just &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; normally after a commit, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git push csc master&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And the files should show up automatically in your www folder (or your club&#039;s www folder, if you are a club rep).&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have any files in your repo which you don&#039;t want to be served from your website, use a [https://httpd.apache.org/docs/2.4/howto/htaccess.html .htaccess file] in your www folder (make sure this is committed to the git repo). For example, to deny access to the folder named src (in your www folder), you could use the following snippet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
RewriteRule &amp;quot;^src(/.*)?$&amp;quot; - [F,L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See [https://httpd.apache.org/docs/2.4/mod/core.html the Apache documentation] for more details.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need help, email &amp;lt;tt&amp;gt;syscom@csclub.uwaterloo.ca[mailto:syscom@csclub.uwaterloo.ca]&amp;lt;/tt&amp;gt; or come to the CS Club office on the MC 3rd floor across from the Mathsoc CnD.&lt;br /&gt;
&lt;br /&gt;
== DNS and Your Domain Name ==&lt;br /&gt;
&lt;br /&gt;
You can serve files without any additional configuration by placing them in your &amp;lt;tt&amp;gt;www&amp;lt;/tt&amp;gt; directory and accessing them at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;userid&amp;lt;/tt&amp;gt; is your CSC user ID. However, many of our members and clubs prefer to use a custom domain name.&lt;br /&gt;
&lt;br /&gt;
Note that this means you &#039;&#039;do not&#039;&#039; have to register a domain name to be able to use our services. You can just put a website at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== uwaterloo.ca domain Names ===&lt;br /&gt;
&lt;br /&gt;
If you represent a UWaterloo organization, you may be eligible for a custom &amp;lt;tt&amp;gt;uwaterloo.ca&amp;lt;/tt&amp;gt; domain name, such as &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;. We can request this on your behalf.&lt;br /&gt;
&lt;br /&gt;
In order to do so, we must have verified that the organization is a legitimate UWaterloo-affiliated group, and that you, the representative, are authorized to request a domain name on their behalf. This all takes place when you request [[Club Hosting|club hosting]] with the Computer Science Club.&lt;br /&gt;
&lt;br /&gt;
Once you register as a club representative of your particular organization, you can send an email from your official club account to syscom@csclub.uwaterloo.ca to request the domain &amp;lt;tt&amp;gt;yourdomain.uwaterloo.ca&amp;lt;/tt&amp;gt;. Assuming it is available, we will file a ticket and request the domain in your name.&lt;br /&gt;
&lt;br /&gt;
=== Your personal domain name ===&lt;br /&gt;
&lt;br /&gt;
These virtual hosts must be approved by the Executive and Systems Committee. If interested, send syscom@csclub.uwaterloo.ca an email. If your request is approved, the Systems Committee will direct you to create a CNAME record for your domain and point it at &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you are interested in receiving mail or having other records on your domain, the apex of your domain cannot be a CNAME. If this is the case, then your domain should contain an &amp;quot;A&amp;quot; record of &amp;lt;tt&amp;gt;129.97.134.17&amp;lt;/tt&amp;gt; and a (optional, but recommended) &amp;quot;AAAA&amp;quot; record of &amp;lt;tt&amp;gt;2620:101:f000:4901:c5c::caff:e12e&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you want TLS on your personal domain, mention this in your email to syscom (syscom: see [[SSL#letsencrypt]]).&lt;br /&gt;
&lt;br /&gt;
== Static Sites ==&lt;br /&gt;
&lt;br /&gt;
You can place all your static content into your web directory, &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you have been approved for a virtual host, you can access this content using your personal domain once the Systems Committee makes the appropriate configuration changes. Here is an example configuration file:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
  	ServerName foobar.uwaterloo.ca&lt;br /&gt;
  	ServerAlias *.foobar.uwaterloo.ca foobar&lt;br /&gt;
  	ServerAdmin your@email.here.tld&lt;br /&gt;
  &lt;br /&gt;
  	DocumentRoot /users/userid/www/&lt;br /&gt;
  &lt;br /&gt;
  	ErrorLog /var/log/apache2/luser-userid-error.log&lt;br /&gt;
  	CustomLog /var/log/apache2/luser-userid-access.log combined&lt;br /&gt;
  &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dynamic Sites ==&lt;br /&gt;
&lt;br /&gt;
If you require use of a database, we offer you the sole choice of MySQL. See [[MySQL|this guide]] for how to create your database and connect to MySQL.&lt;br /&gt;
&lt;br /&gt;
=== ***NOTICE*** ===&lt;br /&gt;
&lt;br /&gt;
  We &#039;&#039;&#039;STRONGLY&#039;&#039;&#039; discourage the use of content management systems such as&lt;br /&gt;
  WordPress. These packages are notorious for the number of security&lt;br /&gt;
  vulnerabilities they contain and pose a threat to our systems if they are not&lt;br /&gt;
  kept up to date. The Systems Committee &#039;&#039;&#039;WILL,&#039;&#039;&#039; at its discretion, disable&lt;br /&gt;
  any website using a package such as WordPress that is not updated to the latest&lt;br /&gt;
  version or that is found to contain exploitable security flaws. In such a case,&lt;br /&gt;
  the member or club serving that site will be notified of the termination; the&lt;br /&gt;
  site will not be re-enabled until the issues are addressed.&lt;br /&gt;
&lt;br /&gt;
When pages are parked, access to them is restricted to on-campus IPs, so you can still fix your page, but anyone off-campus will not be able to access it, and will be shown this page instead: [https://csclub.uwaterloo.ca/~sysadmin/insecure/ https://csclub.uwaterloo.ca/~sysadmin/insecure/].&lt;br /&gt;
&lt;br /&gt;
=== Using PHP ===&lt;br /&gt;
&lt;br /&gt;
Because we use Apache, it&#039;s as simple as placing your &amp;lt;tt&amp;gt;index.php&amp;lt;/tt&amp;gt; file in your &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;. That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
You can even include rewrite rules in an &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; file in your web directory.&lt;br /&gt;
&lt;br /&gt;
=== Reverse Proxy (Python, Ruby, Perl, etc.) ===&lt;br /&gt;
&lt;br /&gt;
(In progress... Cliff Notes below)&lt;br /&gt;
&lt;br /&gt;
If computationally expensive, please run the server on a general-use server and proxy to Caffeine.&lt;br /&gt;
&lt;br /&gt;
If Python, (1) use a [http://docs.python-guide.org/en/latest/dev/virtualenvs/ virtual environment] (2) host your app (within the virtualenv) with [http://gunicorn.org/ Gunicorn] on a high port (but campus firewalled, i.e. NOT Ports 28000-28500).&lt;br /&gt;
&lt;br /&gt;
If Ruby (Note, I&#039;ve never used Ruby so take this with a grain of salt), use [http://unicorn.bogomips.org/ Unicorn] in the same way.&lt;br /&gt;
&lt;br /&gt;
==== .htaccess Config ====&lt;br /&gt;
&lt;br /&gt;
Put the following in the appropriate .htaccess file (e.g. if you were running your app at ~ctdalek/python-app, put the .htaccess in ~ctdalek/www/python-app alongside the static files). Replace HOST with localhost if running on Caffeine or the hostname if running elsewhere; replace port with your chosen port number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
&lt;br /&gt;
# If you want websockets, uncomment this:&lt;br /&gt;
#RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]&lt;br /&gt;
#RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]&lt;br /&gt;
#RewriteRule .* ws://HOST:RANDOM_PORT%{REQUEST_URI} [L,P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;index.html&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/&amp;quot; [P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;^(.*)$&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/$1&amp;quot; [P]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Requiring Authentication ==&lt;br /&gt;
&amp;lt;b&amp;gt;**UPDATE**&amp;lt;/b&amp;gt;: CAS is deprecated; the instructions below are left for historical purposes only. The University of Waterloo now uses [[ADFS]] for web authentication. Unfortunately the Apache module which we use to integrate with ADFS (mod_auth_mellon) cannot be used from .htaccess files, which means that regular members cannot use this. ([https://github.com/latchset/mod_auth_mellon/issues/82 Here] is the relevant GitHub issue; as of this writing, it is still open.) If you require UW authentication for your website, please send an email to syscom and we will configure Apache for you.&lt;br /&gt;
&lt;br /&gt;
=== CAS (no longer works) ===&lt;br /&gt;
You can require users to authenticate through the University&#039;s Central Authentication System (CAS) by adding the following contents to your .htaccess configuration file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AuthType CAS&lt;br /&gt;
Require valid-user&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can replace &amp;lt;pre&amp;gt;Require valid-user&amp;lt;/pre&amp;gt; with &amp;lt;pre&amp;gt;Require user ctdalek&amp;lt;/pre&amp;gt; to restrict to specific users. See https://doubledoublesecurity.ca/uw/cas/user.html for more information.&lt;br /&gt;
&lt;br /&gt;
== Syscom ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling insecure or infringing sites ===&lt;br /&gt;
&lt;br /&gt;
To disable a webspace that has known security vulnerabilities add the following snippet to `/etc/apache2/conf-available/disable-vuln-site.conf`. This rewrites all accesses of the directory or its children to the given file. Note that our disable page always returns HTTP status code 503 (Service Unavailable).&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory /users/$BADUSER/www&amp;gt;&lt;br /&gt;
     AllowOverride None&lt;br /&gt;
     Redirect 503 /&lt;br /&gt;
     ErrorDocument 503 /~sysadmin/insecure/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For infringing sites:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADUSER/www/infringing-directory&amp;quot;&amp;gt;&lt;br /&gt;
    AllowOverride None&lt;br /&gt;
    Redirect 503 /&lt;br /&gt;
    ErrorDocument 503 /~sysadmin/infringing/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For club domains (e.g. club1.uwaterloo.ca), redirect to the CSC domain instead:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   AllowOverride None&lt;br /&gt;
   RewriteEngine On&lt;br /&gt;
   RewriteRule . &amp;lt;nowiki&amp;gt;https://csclub.uwaterloo.ca/~sysadmin/insecure/index.php&amp;lt;/nowiki&amp;gt; [L,P]&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For WordPress sites specifically, insert a snippet similar to the following into conf-enabled/disable-wordpress.conf:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   Include snippets/disable-wordpress.conf&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Expired Websites ===&lt;br /&gt;
&lt;br /&gt;
There is a cron job running hourly on caffeine which disables expired member&#039;s websites (and re-enables them when they&#039;ve renewed their membership).&lt;br /&gt;
&lt;br /&gt;
The script is here: https://git.csclub.uwaterloo.ca/public/expire-sites&lt;br /&gt;
&lt;br /&gt;
Some highlights:&lt;br /&gt;
&lt;br /&gt;
* The script provides a 1-month grace period (corresponding to the grace period of pam-csc)&lt;br /&gt;
* The expired page returns HTTP status code of 503 (Service Unavailable)&lt;br /&gt;
&lt;br /&gt;
=== Fighting AI scrappers ===&lt;br /&gt;
We use [https://github.com/TecharoHQ/anubis Anubis] to block excess AI scrappers. This sits between Apache2 and the real application to insert a proof-of-work challenge for the browser to solve, before proceeding to provide the actual content.&lt;br /&gt;
&lt;br /&gt;
Since Anubis requires JavaScript, it is only selectively enabled on sites that a) is currently getting excessively scraped and b) need JavaScript already.&lt;br /&gt;
&lt;br /&gt;
Currently, only [[Git Hosting]] is protected.&lt;br /&gt;
&lt;br /&gt;
See &amp;lt;code&amp;gt;caffeine:/etc/anubis&amp;lt;/code&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
Anubis might break services running on the CSC servers (e.g. Renovate Bot). To fix this, simply add the service into the list of Anubis&#039; exceptions (gitea.botPolicies.json). Afterwards, restart Anubis and Apache. WARNING: This might break Git.&lt;br /&gt;
&lt;br /&gt;
=== Sample Apache config for website with both a custom domain and a UW subdomain ===&lt;br /&gt;
&lt;br /&gt;
 Define ENTITY_NAME pmclub&lt;br /&gt;
 Define CUSTOM_DOMAIN puremath.club&lt;br /&gt;
 Define UW_SUBDOMAIN ${ENTITY_NAME}.uwaterloo.ca&lt;br /&gt;
 Define ADMIN_EMAIL ${ENTITY_NAME}@csclub.uwaterloo.ca&lt;br /&gt;
 Define ENTITY_HOME https://csclub.uwaterloo.ca/~${ENTITY_NAME}&lt;br /&gt;
 &lt;br /&gt;
 Define APACHE_LOG_DIR /var/log/apache2&lt;br /&gt;
 Define ERROR_LOG ${APACHE_LOG_DIR}/${ENTITY_NAME}-error.log&lt;br /&gt;
 Define CUSTOM_LOG &amp;quot;${APACHE_LOG_DIR}/${ENTITY_NAME}-access.log combined&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN} ${UW_SUBDOMAIN} *.${UW_SUBDOMAIN} ${ENTITY_NAME}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	DocumentRoot /users/${ENTITY_NAME}/www&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent /&amp;lt;special page&amp;gt; ${ENTITY_HOME}/&amp;lt;special path&amp;gt;/&amp;lt;special file&amp;gt;&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAlias *.${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;/div&gt;</summary>
		<author><name>K57chan</name></author>
	</entry>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5375</id>
		<title>Web Hosting</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Web_Hosting&amp;diff=5375"/>
		<updated>2025-06-28T00:02:55Z</updated>

		<summary type="html">&lt;p&gt;K57chan: Added documentation on fixing Anubis when it kills other bots.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The CSC offers web hosting for [[Club Hosting|clubs]] and [http://csclub.uwaterloo.ca/about/ our members] in accordance with our [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. This is a quick guide for the kinds of hosting we offer on our webserver, &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;, also known as [[Machine List#caffeine|caffeine]].&lt;br /&gt;
&lt;br /&gt;
We run an Apache httpd webserver and we offer you the use of a [[MySQL|MySQL database]].&lt;br /&gt;
&lt;br /&gt;
== What can I host on my website? ==&lt;br /&gt;
&lt;br /&gt;
Web hosting is provided in accordance with the CSC [http://csclub.uwaterloo.ca/services/machine_usage Machine Usage Agreement]. As a reminder, you are &#039;&#039;&#039;not permitted&#039;&#039;&#039; to host any of the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ads.&#039;&#039;&#039; Advertisements are not permitted because using our machines for commercial purposes is forbidden by university policy.&lt;br /&gt;
* &#039;&#039;&#039;Your start-up&#039;s website.&#039;&#039;&#039; Again, commercial use of our hosting is not permitted.&lt;br /&gt;
* &#039;&#039;&#039;Unauthorized copyrighted materials.&#039;&#039;&#039; Violating the law is a violation of our Machine Usage Agreement.&lt;br /&gt;
&lt;br /&gt;
Please note that &#039;&#039;&#039;this is not an exhaustive list. Websites may be taken down &#039;&#039;without notice&#039;&#039;&#039;&#039;&#039; at the discretion of the Systems Committee. (We will always let you know that we took your site down, but if it is breaking our shared environment, we can&#039;t provide an advance warning.)&lt;br /&gt;
&lt;br /&gt;
Some great examples of things members host on our webserver:&lt;br /&gt;
&lt;br /&gt;
* Academic projects!&lt;br /&gt;
* A personal website or blog!&lt;br /&gt;
* [[Club Hosting|Club websites!]]&lt;br /&gt;
&lt;br /&gt;
== How do I make a website? ==&lt;br /&gt;
&lt;br /&gt;
If you just want to show some static content (e.g. blog posts, club information, technical articles), then we recommend that you use a static site generator (SSG). Static sites are faster, simpler and more secure than CMSs like WordPress (dynamic and written in PHP) for small sites. We routinely disable WordPress sites that are more than a few weeks out of date (or if a critical security flaw is disclosed).&lt;br /&gt;
&lt;br /&gt;
Here are some SSGs which require little to no coding experience, and also have a great selection of themes to choose from:&lt;br /&gt;
&lt;br /&gt;
* [https://jekyllrb.com/ Jekyll] (accepts Markdown, Liquid and HTML)&lt;br /&gt;
* [https://gohugo.io/ Hugo] (accepts a wide variety of formats, including Markdown and JSON)&lt;br /&gt;
* [https://hexo.io/ Hexo] (accepts Markdown and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.11ty.dev/ Eleventy] (accepts Markdown, Liquid, HTML, and various Javascript-based templating engines)&lt;br /&gt;
* [https://www.getzola.org/ Zola] (accepts Markdown and Tera)&lt;br /&gt;
* [https://blog.getpelican.com/ Pelican] (accepts Markdown, reStructuredText and Jinja2)&lt;br /&gt;
&lt;br /&gt;
[https://astro.build/ Astro] is an excellent static site builder which integrates with a wide variety of JS-based frameworks (including React, Vue, Svelte and Solid), but requires a bit more coding experience.&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with React.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nextjs.org/ Next.js]&lt;br /&gt;
* [https://www.gatsbyjs.com/ Gatsby.js]&lt;br /&gt;
&lt;br /&gt;
These SSGs require some experience with Vue.js:&lt;br /&gt;
&lt;br /&gt;
* [https://nuxtjs.org/ Nuxt.js]&lt;br /&gt;
* [https://vuepress.vuejs.org/ Vuepress]&lt;br /&gt;
* [https://vitepress.vuejs.org/ Vitepress]&lt;br /&gt;
* [https://gridsome.org/ Gridsome]&lt;br /&gt;
&lt;br /&gt;
[https://jamstack.org/generators/ Here] is an awesome list of other generators to explore, if you are interested.&lt;br /&gt;
&lt;br /&gt;
=== Transferring your files to the CSC servers ===&lt;br /&gt;
If you just need to transfer a single file, then the easiest option is to use the &amp;lt;code&amp;gt;scp&amp;lt;/code&amp;gt; command (which is available on all major operating systems), e.g.&lt;br /&gt;
&lt;br /&gt;
  scp /path/to/your/file your_username@corn-syrup.csclub.uwaterloo.ca:~/&lt;br /&gt;
&lt;br /&gt;
This will copy /path/to/your/file from your local PC to your CSC home directory (we use NFS, so you can access it from any of the general-use machines).&lt;br /&gt;
&lt;br /&gt;
However, we strongly recommend setting up a git repository in your home directory instead.&lt;br /&gt;
&lt;br /&gt;
=== Setting up a git repository ===&lt;br /&gt;
All of the files in the &amp;lt;code&amp;gt;www&amp;lt;/code&amp;gt; directory in your home directory are accessible from csclub.uwaterloo.ca/~your_username. If everything is set up right, this can provide a GitHub Pages-like experience.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Create a &amp;quot;bare&amp;quot; git repository in your home directory (on the CSC machines). You will git push/pull from this directory.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Switch to the Unix user for your club, and use the &amp;lt;code&amp;gt;--shared&amp;lt;/code&amp;gt; option to automatically add group write permissions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
become_club myclub&lt;br /&gt;
cd ~&lt;br /&gt;
mkdir myrepo.git&lt;br /&gt;
cd myrepo.git&lt;br /&gt;
git init --bare --shared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Create a git post-receive hook which will automatically deploy your website whenever you git push. Paste the following script into hooks/post-receive (in the bare repo you created earlier). You may wish to customize it a bit first.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
# Uncomment this to echo the commands as they are executed&lt;br /&gt;
#set -x&lt;br /&gt;
shopt -s dotglob&lt;br /&gt;
# FOR CLUB REPS ONLY: set the following variable to e.g. /users/myclub/www&lt;br /&gt;
DEPLOYMENT_DIR=~/www&lt;br /&gt;
&lt;br /&gt;
while read oldrev newrev refname; do&lt;br /&gt;
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)&lt;br /&gt;
    # Only the master branch will be deployed&lt;br /&gt;
    if [ &amp;quot;$branch&amp;quot; != master ]; then&lt;br /&gt;
        continue&lt;br /&gt;
    fi&lt;br /&gt;
    rm -rf $DEPLOYMENT_DIR/*&lt;br /&gt;
    git --work-tree=$DEPLOYMENT_DIR checkout -f $branch&lt;br /&gt;
    # FOR CLUB REPS ONLY: uncomment the following lines and replace &#039;myclub&#039;&lt;br /&gt;
    # with the Unix group name of your club&lt;br /&gt;
    #chgrp -R myclub $DEPLOYMENT_DIR&lt;br /&gt;
    #chmod -R g+w $DEPLOYMENT_DIR&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
(The script was adapted from [https://peteris.rocks/blog/deploy-your-website-with-git/ here].)&lt;br /&gt;
&lt;br /&gt;
Make the script executable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod +x hooks/post-receive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;For club reps&amp;lt;/b&amp;gt;: Make sure the www directory is group-writable. Switch to the Unix user of your club and run:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+w ~/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have not done so already, add your public SSH key to your ~/.ssh/authorized_keys file (on the CSC machines). See [https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key here] for a tutorial.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
On your local computer, add [[Machine_List|any CSC machine]] as a remote of your git repo.&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For members:&amp;lt;br&amp;gt;&lt;br /&gt;
Just use the directory of your git repo, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;For club reps:&amp;lt;br&amp;gt;&lt;br /&gt;
Use the full path of the repo in your club user&#039;s home directory, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git remote add csc your_username@corn-syrup.csclub.uwaterloo.ca:/users/myclub/myrepo.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Now you can just &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; normally after a commit, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git push csc master&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And the files should show up automatically in your www folder (or your club&#039;s www folder, if you are a club rep).&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If you have any files in your repo which you don&#039;t want to be served from your website, use a [https://httpd.apache.org/docs/2.4/howto/htaccess.html .htaccess file] in your www folder (make sure this is committed to the git repo). For example, to deny access to the folder named src (in your www folder), you could use the following snippet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
RewriteRule &amp;quot;^src(/.*)?$&amp;quot; - [F,L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See [https://httpd.apache.org/docs/2.4/mod/core.html the Apache documentation] for more details.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need help, email &amp;lt;tt&amp;gt;syscom@csclub.uwaterloo.ca[mailto:syscom@csclub.uwaterloo.ca]&amp;lt;/tt&amp;gt; or come to the CS Club office on the MC 3rd floor across from the Mathsoc CnD.&lt;br /&gt;
&lt;br /&gt;
== DNS and Your Domain Name ==&lt;br /&gt;
&lt;br /&gt;
You can serve files without any additional configuration by placing them in your &amp;lt;tt&amp;gt;www&amp;lt;/tt&amp;gt; directory and accessing them at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;userid&amp;lt;/tt&amp;gt; is your CSC user ID. However, many of our members and clubs prefer to use a custom domain name.&lt;br /&gt;
&lt;br /&gt;
Note that this means you &#039;&#039;do not&#039;&#039; have to register a domain name to be able to use our services. You can just put a website at &amp;lt;tt&amp;gt;http://csclub.uwaterloo.ca/~userid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== uwaterloo.ca domain Names ===&lt;br /&gt;
&lt;br /&gt;
If you represent a UWaterloo organization, you may be eligible for a custom &amp;lt;tt&amp;gt;uwaterloo.ca&amp;lt;/tt&amp;gt; domain name, such as &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;. We can request this on your behalf.&lt;br /&gt;
&lt;br /&gt;
In order to do so, we must have verified that the organization is a legitimate UWaterloo-affiliated group, and that you, the representative, are authorized to request a domain name on their behalf. This all takes place when you request [[Club Hosting|club hosting]] with the Computer Science Club.&lt;br /&gt;
&lt;br /&gt;
Once you register as a club representative of your particular organization, you can send an email from your official club account to syscom@csclub.uwaterloo.ca to request the domain &amp;lt;tt&amp;gt;yourdomain.uwaterloo.ca&amp;lt;/tt&amp;gt;. Assuming it is available, we will file a ticket and request the domain in your name.&lt;br /&gt;
&lt;br /&gt;
=== Your personal domain name ===&lt;br /&gt;
&lt;br /&gt;
These virtual hosts must be approved by the Executive and Systems Committee. If interested, send syscom@csclub.uwaterloo.ca an email. If your request is approved, the Systems Committee will direct you to create a CNAME record for your domain and point it at &amp;lt;tt&amp;gt;csclub.uwaterloo.ca&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you are interested in receiving mail or having other records on your domain, the apex of your domain cannot be a CNAME. If this is the case, then your domain should contain an &amp;quot;A&amp;quot; record of &amp;lt;tt&amp;gt;129.97.134.17&amp;lt;/tt&amp;gt; and a (optional, but recommended) &amp;quot;AAAA&amp;quot; record of &amp;lt;tt&amp;gt;2620:101:f000:4901:c5c::caff:e12e&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you want TLS on your personal domain, mention this in your email to syscom (syscom: see [[SSL#letsencrypt]]).&lt;br /&gt;
&lt;br /&gt;
== Static Sites ==&lt;br /&gt;
&lt;br /&gt;
You can place all your static content into your web directory, &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you have been approved for a virtual host, you can access this content using your personal domain once the Systems Committee makes the appropriate configuration changes. Here is an example configuration file:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
  	ServerName foobar.uwaterloo.ca&lt;br /&gt;
  	ServerAlias *.foobar.uwaterloo.ca foobar&lt;br /&gt;
  	ServerAdmin your@email.here.tld&lt;br /&gt;
  &lt;br /&gt;
  	DocumentRoot /users/userid/www/&lt;br /&gt;
  &lt;br /&gt;
  	ErrorLog /var/log/apache2/luser-userid-error.log&lt;br /&gt;
  	CustomLog /var/log/apache2/luser-userid-access.log combined&lt;br /&gt;
  &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dynamic Sites ==&lt;br /&gt;
&lt;br /&gt;
If you require use of a database, we offer you the sole choice of MySQL. See [[MySQL|this guide]] for how to create your database and connect to MySQL.&lt;br /&gt;
&lt;br /&gt;
=== ***NOTICE*** ===&lt;br /&gt;
&lt;br /&gt;
  We &#039;&#039;&#039;STRONGLY&#039;&#039;&#039; discourage the use of content management systems such as&lt;br /&gt;
  WordPress. These packages are notorious for the number of security&lt;br /&gt;
  vulnerabilities they contain and pose a threat to our systems if they are not&lt;br /&gt;
  kept up to date. The Systems Committee &#039;&#039;&#039;WILL,&#039;&#039;&#039; at its discretion, disable&lt;br /&gt;
  any website using a package such as WordPress that is not updated to the latest&lt;br /&gt;
  version or that is found to contain exploitable security flaws. In such a case,&lt;br /&gt;
  the member or club serving that site will be notified of the termination; the&lt;br /&gt;
  site will not be re-enabled until the issues are addressed.&lt;br /&gt;
&lt;br /&gt;
When pages are parked, access to them is restricted to on-campus IPs, so you can still fix your page, but anyone off-campus will not be able to access it, and will be shown this page instead: [https://csclub.uwaterloo.ca/~sysadmin/insecure/ https://csclub.uwaterloo.ca/~sysadmin/insecure/].&lt;br /&gt;
&lt;br /&gt;
=== Using PHP ===&lt;br /&gt;
&lt;br /&gt;
Because we use Apache, it&#039;s as simple as placing your &amp;lt;tt&amp;gt;index.php&amp;lt;/tt&amp;gt; file in your &amp;lt;tt&amp;gt;/users/userid/www&amp;lt;/tt&amp;gt;. That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
You can even include rewrite rules in an &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; file in your web directory.&lt;br /&gt;
&lt;br /&gt;
=== Reverse Proxy (Python, Ruby, Perl, etc.) ===&lt;br /&gt;
&lt;br /&gt;
(In progress... Cliff Notes below)&lt;br /&gt;
&lt;br /&gt;
If computationally expensive, please run the server on a general-use server and proxy to Caffeine.&lt;br /&gt;
&lt;br /&gt;
If Python, (1) use a [http://docs.python-guide.org/en/latest/dev/virtualenvs/ virtual environment] (2) host your app (within the virtualenv) with [http://gunicorn.org/ Gunicorn] on a high port (but campus firewalled, i.e. NOT Ports 28000-28500).&lt;br /&gt;
&lt;br /&gt;
If Ruby (Note, I&#039;ve never used Ruby so take this with a grain of salt), use [http://unicorn.bogomips.org/ Unicorn] in the same way.&lt;br /&gt;
&lt;br /&gt;
==== .htaccess Config ====&lt;br /&gt;
&lt;br /&gt;
Put the following in the appropriate .htaccess file (e.g. if you were running your app at ~ctdalek/python-app, put the .htaccess in ~ctdalek/www/python-app alongside the static files). Replace HOST with localhost if running on Caffeine or the hostname if running elsewhere; replace port with your chosen port number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteEngine On&lt;br /&gt;
&lt;br /&gt;
# If you want websockets, uncomment this:&lt;br /&gt;
#RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]&lt;br /&gt;
#RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]&lt;br /&gt;
#RewriteRule .* ws://HOST:RANDOM_PORT%{REQUEST_URI} [L,P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;index.html&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/&amp;quot; [P]&lt;br /&gt;
&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-d&lt;br /&gt;
RewriteCond %{SCRIPT_FILENAME} !-f&lt;br /&gt;
RewriteRule &amp;quot;^(.*)$&amp;quot; &amp;quot;http://HOST:RANDOM_PORT/$1&amp;quot; [P]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Requiring Authentication ==&lt;br /&gt;
&amp;lt;b&amp;gt;**UPDATE**&amp;lt;/b&amp;gt;: CAS is deprecated; the instructions below are left for historical purposes only. The University of Waterloo now uses [[ADFS]] for web authentication. Unfortunately the Apache module which we use to integrate with ADFS (mod_auth_mellon) cannot be used from .htaccess files, which means that regular members cannot use this. ([https://github.com/latchset/mod_auth_mellon/issues/82 Here] is the relevant GitHub issue; as of this writing, it is still open.) If you require UW authentication for your website, please send an email to syscom and we will configure Apache for you.&lt;br /&gt;
&lt;br /&gt;
=== CAS (no longer works) ===&lt;br /&gt;
You can require users to authenticate through the University&#039;s Central Authentication System (CAS) by adding the following contents to your .htaccess configuration file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AuthType CAS&lt;br /&gt;
Require valid-user&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can replace &amp;lt;pre&amp;gt;Require valid-user&amp;lt;/pre&amp;gt; with &amp;lt;pre&amp;gt;Require user ctdalek&amp;lt;/pre&amp;gt; to restrict to specific users. See https://doubledoublesecurity.ca/uw/cas/user.html for more information.&lt;br /&gt;
&lt;br /&gt;
== Syscom ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling insecure or infringing sites ===&lt;br /&gt;
&lt;br /&gt;
To disable a webspace that has known security vulnerabilities add the following snippet to `/etc/apache2/conf-available/disable-vuln-site.conf`. This rewrites all accesses of the directory or its children to the given file. Note that our disable page always returns HTTP status code 503 (Service Unavailable).&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory /users/$BADUSER/www&amp;gt;&lt;br /&gt;
     AllowOverride None&lt;br /&gt;
     Redirect 503 /&lt;br /&gt;
     ErrorDocument 503 /~sysadmin/insecure/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For infringing sites:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADUSER/www/infringing-directory&amp;quot;&amp;gt;&lt;br /&gt;
    AllowOverride None&lt;br /&gt;
    Redirect 503 /&lt;br /&gt;
    ErrorDocument 503 /~sysadmin/infringing/index.html&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For club domains (e.g. club1.uwaterloo.ca), redirect to the CSC domain instead:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   AllowOverride None&lt;br /&gt;
   RewriteEngine On&lt;br /&gt;
   RewriteRule . &amp;lt;nowiki&amp;gt;https://csclub.uwaterloo.ca/~sysadmin/insecure/index.php&amp;lt;/nowiki&amp;gt; [L,P]&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For WordPress sites specifically, insert a snippet similar to the following into conf-enabled/disable-wordpress.conf:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Directory &amp;quot;/users/$BADCLUB/www&amp;quot;&amp;gt;&lt;br /&gt;
   Include snippets/disable-wordpress.conf&lt;br /&gt;
 &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Expired Websites ===&lt;br /&gt;
&lt;br /&gt;
There is a cron job running hourly on caffeine which disables expired member&#039;s websites (and re-enables them when they&#039;ve renewed their membership).&lt;br /&gt;
&lt;br /&gt;
The script is here: https://git.csclub.uwaterloo.ca/public/expire-sites&lt;br /&gt;
&lt;br /&gt;
Some highlights:&lt;br /&gt;
&lt;br /&gt;
* The script provides a 1-month grace period (corresponding to the grace period of pam-csc)&lt;br /&gt;
* The expired page returns HTTP status code of 503 (Service Unavailable)&lt;br /&gt;
&lt;br /&gt;
=== Fighting AI scrappers ===&lt;br /&gt;
We use [https://github.com/TecharoHQ/anubis Anubis] to block excess AI scrappers. This sits between Apache2 and the real application to insert a proof-of-work challenge for the browser to solve, before proceeding to provide the actual content.&lt;br /&gt;
&lt;br /&gt;
Since Anubis requires JavaScript, it is only selectively enabled on sites that a) is currently getting excessively scraped and b) need JavaScript already.&lt;br /&gt;
&lt;br /&gt;
Currently, only [[Git Hosting]] is protected.&lt;br /&gt;
&lt;br /&gt;
See &amp;lt;code&amp;gt;caffeine:/etc/anubis&amp;lt;/code&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
Anubis might break certain bots running on the CSC servers (e.g. Renovate Bot). To fix this, simply add the service into the list of Anubis&#039; exceptions (gitea.botPolicies.json). This might break Git.&lt;br /&gt;
&lt;br /&gt;
=== Sample Apache config for website with both a custom domain and a UW subdomain ===&lt;br /&gt;
&lt;br /&gt;
 Define ENTITY_NAME pmclub&lt;br /&gt;
 Define CUSTOM_DOMAIN puremath.club&lt;br /&gt;
 Define UW_SUBDOMAIN ${ENTITY_NAME}.uwaterloo.ca&lt;br /&gt;
 Define ADMIN_EMAIL ${ENTITY_NAME}@csclub.uwaterloo.ca&lt;br /&gt;
 Define ENTITY_HOME https://csclub.uwaterloo.ca/~${ENTITY_NAME}&lt;br /&gt;
 &lt;br /&gt;
 Define APACHE_LOG_DIR /var/log/apache2&lt;br /&gt;
 Define ERROR_LOG ${APACHE_LOG_DIR}/${ENTITY_NAME}-error.log&lt;br /&gt;
 Define CUSTOM_LOG &amp;quot;${APACHE_LOG_DIR}/${ENTITY_NAME}-access.log combined&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN} ${UW_SUBDOMAIN} *.${UW_SUBDOMAIN} ${ENTITY_NAME}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${CUSTOM_DOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAlias *.${CUSTOM_DOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	DocumentRoot /users/${ENTITY_NAME}/www&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent /&amp;lt;special page&amp;gt; ${ENTITY_HOME}/&amp;lt;special path&amp;gt;/&amp;lt;special file&amp;gt;&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;VirtualHost csclub:443&amp;gt;&lt;br /&gt;
 	SSLEngine on&lt;br /&gt;
 	SSLCertificateFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/fullchain.pem&lt;br /&gt;
 	SSLCertificateKeyFile /etc/letsencrypt/live/${UW_SUBDOMAIN}/privkey.pem&lt;br /&gt;
 	SSLStrictSNIVHostCheck on&lt;br /&gt;
 &lt;br /&gt;
 	ServerName ${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAlias *.${UW_SUBDOMAIN}&lt;br /&gt;
 	ServerAdmin ${ADMIN_EMAIL}&lt;br /&gt;
 &lt;br /&gt;
 	Redirect permanent / https://${CUSTOM_DOMAIN}/&lt;br /&gt;
 &lt;br /&gt;
 	ErrorLog ${ERROR_LOG}&lt;br /&gt;
 	CustomLog ${CUSTOM_LOG}&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;/div&gt;</summary>
		<author><name>K57chan</name></author>
	</entry>
</feed>