# Adding a New `*.nillnode.com` Subdomain

This server uses Apache on Ubuntu with Let's Encrypt certificates from Certbot.

Current patterns in use:

- `manager-dashboard.nillnode.com` -> Apache reverse proxy -> `127.0.0.1:3000`
- `financials.nillnode.com` -> Apache `mod_wsgi` -> `/var/www/html/financials/wsgi.py`
- `nillnode.com` and `www.nillnode.com` -> `/var/www/html`
- `chasetheduedate.com` stays on its own domain and its own vhosts

## 1. Create DNS

In Namecheap DNS, add a new record for the subdomain.

Recommended pattern:

- `Type`: `CNAME`
- `Host`: just the subdomain label, for example `myapp`
- `Value`: `sayre.duckdns.org`

Example:

- `myapp.nillnode.com`:
  - `Host`: `myapp`
  - `Value`: `sayre.duckdns.org`

Alternative:

- Use an `A` record pointing to the current public IP if you do not want to use DuckDNS.

## 2. Choose the hosting pattern

There are two main patterns already used on this server.

### Pattern A: Reverse proxy to a local app port

Use this for Node, Express, Flask dev server, or any service already listening on a port like `3000` or `5000`.

Example HTTP vhost:

```apache
<VirtualHost *:80>
    ServerName myapp.nillnode.com
    ServerAdmin webmaster@localhost

    ProxyPreserveHost On
    ProxyRequests Off

    RequestHeader set X-Forwarded-Proto "http"
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    ErrorLog ${APACHE_LOG_DIR}/myapp.nillnode.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.nillnode.com_access.log combined

    RewriteEngine On
    RewriteCond %{SERVER_NAME} =myapp.nillnode.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
```

Example HTTPS vhost:

```apache
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName myapp.nillnode.com
    ServerAdmin webmaster@localhost

    ProxyPreserveHost On
    ProxyRequests Off

    RequestHeader set X-Forwarded-Proto "https"
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    ErrorLog ${APACHE_LOG_DIR}/myapp.nillnode.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.nillnode.com_access.log combined

    SSLCertificateFile /etc/letsencrypt/live/myapp.nillnode.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/myapp.nillnode.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
```

### Pattern B: Apache `mod_wsgi` for a Flask app

Use this for Python apps deployed directly with Apache.

Example HTTP vhost:

```apache
<VirtualHost *:80>
    ServerName myapp.nillnode.com
    ServerAdmin webmaster@localhost

    WSGIDaemonProcess myapp_nillnode python-home=/var/www/html/myapp/.venv python-path=/var/www/html/myapp
    WSGIProcessGroup myapp_nillnode
    WSGIScriptAlias / /var/www/html/myapp/wsgi.py

    <Directory /var/www/html/myapp>
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/myapp.nillnode.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.nillnode.com_access.log combined

    RewriteEngine On
    RewriteCond %{SERVER_NAME} =myapp.nillnode.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
```

Example HTTPS vhost:

```apache
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName myapp.nillnode.com
    ServerAdmin webmaster@localhost

    WSGIDaemonProcess myapp_nillnode_ssl python-home=/var/www/html/myapp/.venv python-path=/var/www/html/myapp
    WSGIProcessGroup myapp_nillnode_ssl
    WSGIScriptAlias / /var/www/html/myapp/wsgi.py

    <Directory /var/www/html/myapp>
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/myapp.nillnode.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.nillnode.com_access.log combined

    SSLCertificateFile /etc/letsencrypt/live/myapp.nillnode.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/myapp.nillnode.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
```

Note:

- Use different `WSGIDaemonProcess` names for HTTP and HTTPS, like:
  - `myapp_nillnode`
  - `myapp_nillnode_ssl`

This avoids duplicate daemon-name errors in Apache.

## 3. Save the Apache site files

Put the vhost files in:

```bash
/etc/apache2/sites-available/
```

Typical names:

```bash
myapp.nillnode.com.conf
myapp.nillnode.com-le-ssl.conf
```

## 4. Enable the site and reload Apache

```bash
sudo a2ensite myapp.nillnode.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
```

If the HTTPS file already exists and should be active:

```bash
sudo a2ensite myapp.nillnode.com-le-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
```

## 5. Issue the certificate

For a single subdomain:

```bash
sudo certbot --apache -d myapp.nillnode.com --non-interactive --agree-tos -m hostmaster@nillnode.com --redirect
```

For the apex domain plus `www`:

```bash
sudo certbot --apache -d nillnode.com -d www.nillnode.com --non-interactive --agree-tos -m hostmaster@nillnode.com --redirect
```

## 6. Verify it

From the server:

```bash
curl -I -H 'Host: myapp.nillnode.com' http://127.0.0.1
curl -k -I --resolve myapp.nillnode.com:443:127.0.0.1 https://myapp.nillnode.com
```

Useful checks:

```bash
sudo apache2ctl -S
sudo apache2ctl configtest
sudo certbot certificates
ss -tulpn
```

## 7. Common gotchas

- In Namecheap, the `Host` field should be just the label, like `myapp`, not `myapp.nillnode.com`.
- For proxy apps, make sure the local port is actually listening before testing Apache.
- For Flask `mod_wsgi`, make sure the virtualenv path and `wsgi.py` path are correct.
- For `mod_wsgi`, do not reuse the exact same `WSGIDaemonProcess` name in both HTTP and HTTPS vhosts.
- If DNS looks inconsistent on your workstation, test directly on the server with `curl --resolve` or host headers.
- `chasetheduedate.com` is a separate domain and should stay on its own vhosts unless intentionally migrated.

## 8. Current live examples

- `manager-dashboard.nillnode.com`
- `financials.nillnode.com`
- `nillnode.com`
- `www.nillnode.com`
