Learning Server Admin

My journey to run multiple websites on a single VPS using Caddy

At the moment this is less an article and more of a dumping zone for tidbits I would like to include in an article… And since I published it from the start of my website, I’ll leave it here and let it grow.

Goal

Create a server configuration that can host many different project on unique domains.

Reasoning

I have quite a few little hobby projects and hosting them on a per project basis, as most platform as a service hosting require, ends up being complicated and possibly pricy.

If I can configure a single server to host multiple domains and auto deploy from a GitHub action it would fit the workflow I have become accustom to.

The Next Steps

    • Create a CI workflow to auto deploy projects to the hosting computer from a GitHub action.

Things that work

  • Digital Ocean Server works great and the basic setup guides seem to keep it secure.
  • Caddy Server hosting multiple websites with automatic HTTPS cert renewal.
  • PM2 kinda works, at the moment the process doesn’t reload on restart and I have to manually do it.

Initial Server Setup

  1. Initial Server Setup with Ubuntu 18.04
  2. How To Set Up a Firewall with UFW on Ubuntu 18.04
  3. How To Harden OpenSSH on Ubuntu 18.04
  4. How To Install Node.js on Ubuntu 18.04
  5. How To Set Up a Node.js Application for Production on Ubuntu 18.04

Server Additional Reading

Server Maintenance

DNS

Caddy

Setup

  1. How To Install Go and Set Up a Local Programming Environment on Ubuntu 18.04
  2. How To Host a Website with Caddy on Ubuntu 18.04
  3. Cloudflare module for Caddy

Caddyfile

example.com, www.example.com {
    reverse_proxy 127.0.0.1:3000
    encode gzip

    log {
        output stderr
        format console
        level PANIC
    }

    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
}

The CF_API_TOKEN is located in the /etc/systemd/system/caddy.service

...
[Service]
User=caddy
Group=caddy
Environment=CF_API_TOKEN={your_token_here}
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
...

Node.js

Installing Using a PPA

Download the installation script.

cd ~curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh

You can inspect the contents of the script.

nano nodesource_setup.sh

Run the script to install the NodeSource PPA.

sudo bash nodesource_setup.sh

Install Node.js with the package manager.

sudo apt install nodejs

Check that it was installed.

node -v

npm was also installed.

Because some npm packages will require compiling code from source, the build-essential package should also be installed.

sudo apt install build-essential

PM2

PM2 Setup

  1. pm2 start ecosystem.config.js
  2. pm2 save
  3. run the command generated by pm2 startup systemd
  4. inspect the generated unit file less /etc/systemd/system/pm2-{user_name}.service
  5. sudo systemctl enable pm2-{user_name}
  6. sudo systemctl start pm2-{user_name}
  7. systemctl status pm2-{user_name}

Changing PM2 Configuration After startup

pm2 startOrReload ecosystem.config.js --update-env

This may have resolved the below issue. Just make sure the run pm2 save afterwards. https://stackoverflow.com/q/44508316

I had a lot of trouble changing the configuration of PM2. Before the changes in the ecosystem.config.js would be recognized I had to do the following:

  1. pm2 stop all
  2. pm2 delete all
  3. remove the previously saved configuration pm2 cleardump
  4. sudo systemctl stop pm2-<USERNAME>
  5. remove the pm2 service by running the command generated by pm2 unstartup systemd
  6. sudo systemctl daemon-reload
  7. sudo systemctl reboot restart the server
  8. Then follow the setup steps

systemd

Users

  • deploy
  • app

VSCode Remote