Server Hosting Notes
Server OS Setup
The server that hosts this website is at Digital Ocean.
To setup access I am using ssh keys, which can be created with the
ssh-keygen command, and then copied
to the server with ssh-copy-id.
You also want to make sure that the server has been updated recently,
which can be done with the
apt update && apt upgrade
commands on Ubuntu.
Web Server Setup
Most of my career nowadays has been using AWS infrastructure with services like Lambda and ECS/EKS. While this is great for scalability, it is very overkill for a personal website. So for this site I am using a standard web server to serve static files. This was also slightly influenced by reading Aaron Swartz's blog.
Before we set up the web server, we need to setup a firewall. Since we're using Ubuntu, we can use UFW (Uncomplicated Firewall) for this purpose. The following commands will allow SSH and HTTP/HTTPS traffic:
sudo apt install ufw
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status
For the web server, I decided to use Nginx. Luckily, NGINX is super easy
to get installed and running. Just run
sudo apt-get install nginx. Once it's
installed, it automatically starts running. You can check its status
with sudo systemctl status nginx. You
should be able to visit your server's IP address in a web browser and
see the default NGINX welcome page.
So now we have a server. We need to get our website files onto it! The
first step is making the directory where the website files will live. By
default, NGINX serves files from
/var/www/html. Since you always want
to assume you're going to run multiple websites on a server, it's a good
idea to create a separate directory for each site. So let's create a
directory for this site:
mkdir /var/www/dougs-site.
And now we have to setup the NGINX configuration for this site. For this site, here is the file:
server {
listen 80;
root /var/www/dougs-site;
server_name dsknr.com www.dsknr.com 157.245.119.227;
location / {
try_files $uri $uri/ =404;
}
}
First we need to put that file in the NGINX sites-available directory:
sudo vi /etc/nginx/sites-available/dougs-site. Then we need to create a symbolic link to it in the sites-enabled
directory, which NGINX actually uses:
sudo ln -s /etc/nginx/sites-available/dougs-site
/etc/nginx/sites-enabled/. Finally, we need to test the NGINX configuration for syntax errors
and reload NGINX to apply the changes:
sudo nginx -t && sudo systemctl reload nginx.
Now we need to get the actual files there! For now we're going to use rsync:
rsync -avz --delete ./* tinysite:/var/www/dougs-site/
And this let's you go to the IP address and see the files!
Automated Deployment with GitHub Actions
While manual deployment with rsync works fine, it's much more convenient to have deployments happen automatically when code is pushed to the repository. GitHub Actions can handle this automatically.
The workflow is configured in
.github/workflows/deploy.yml and
runs on every push to the master branch. Here's how it works:
name: Deploy to Server
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
- name: Deploy with rsync
run: |
rsync -avz --delete \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no" \
--exclude '.git' \
--exclude '.github' \
--exclude 'README.md' \
./ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.SERVER_PATH }}
- name: Cleanup
if: always()
run: rm -f ~/.ssh/deploy_key
The workflow uses GitHub Secrets to securely store sensitive information. You need to configure these secrets in your repository settings under Settings → Secrets and variables → Actions:
-
SSH_PRIVATE_KEY - Your SSH private key for server
authentication. Generate a dedicated key pair with
ssh-keygen -t ed25519 -C "github-actions-deploy", add the public key to the server's~/.ssh/authorized_keys, and paste the entire private key (including BEGIN and END lines) into this secret. -
SERVER_HOST - The server hostname or IP address
(e.g.,
157.245.119.227) -
SERVER_USER - SSH username on the server (e.g.,
root) -
SERVER_PATH - Destination path on the server:
/var/www/dougs-site
The workflow uses the same rsync command as manual deployment but with
the --delete flag to remove files on
the server that don't exist in the repository. It excludes Git-related
files and the README to keep the deployment clean.
Now, we need to get our domain name set up. I have my domain hosted with Namecheap, so I will log into my Namecheap account and update the DNS settings to point to my server's IP address.
Finally, in this day and age, every website should be behind HTTPS with a valid SSL certificate. You can use Let's Encrypt to obtain a free SSL certificate and configure NGINX to use it. To install Certbot run:
sudo snap install --classic certbot
And now we need to make the command executable:
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
And then finally run certbot:
sudo certbot --nginx