How I Deploy Static Sites With Nginx
This article will describe how I built and deployed limbo.jpace121.net, including the initial setup I had to do when setting the site up.
Background
I decided I wanted to start self hosting certain web applications a few years ago for educational purposes.
I live in an apartment and have internet provided through the complex, so I don’t have the ability to negotiate for a static IP from my internet provider.
What I do instead is run an Amazon Lightsail instance which runs NGINX and Wireguard.
For non-static sites, I use NGINX to proxy requests from the instance to the actual services I run locally, which are all connected via Wireguard with the Ligthsail instance.
For static sites, proxying down into my home internet it a little silly, so I put any files I need to host directly on the Lightsail instance and serve them from there.
I currently use Google Domains for hosting my domain and DNS. (Though it sounds like that’ll be transferred to Squarespace at some point in the near future…)
I get free HTTPS certs from LetsEncrypt.
Step 1: Setting up DNS records.
The first step was to setup an A record on Google Domains for limbo pointing to the IP of my Lightsail instance.
I do this first so the system has time to propagate the change around before we need the domain name to resolve in the following steps.
Step 2: Set up NGINX.
To set up nginx, I ssh’d into my Lightsail instance using my admin account.
Once I logged in, I cd’d to /etc/nginx/sites-available and copied one of the files that was already there to limbo.jpace121.net.
I modified the file so it had the following the contents
server {
listen 80;
server_name limbo.jpace121.net;
location /.well-known {
alias /var/www/limbo.jpace121.net/.well-known;
}
location / {
return 301 https://limbo.jpace121.net$request_uri;
}
}
server {
listen 443;
server_name limbo.jpace121.net;
ssl_certificate /etc/letsencrypt/live/limbo.jpace121.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/limbo.jpace121.net/privkey.pem;
root /var/www/limbo.jpace121.net/;
location / {
try_files $uri /index.html;
}
location /.well-known {
alias /var/www/limbo.jpace121.net/.well-known;
}
}
and the commented out (using the # symbol) the second server block for now, since we haven’t gotten certs quite yet.
I then created a symbolic link between the new config file in /etc/nginx/sites-enabled which is where nginx actually looks for server files to load (on Debian as configured by default) using the following command:
sudo ln -s /etc/nginx/sites-available/limbo.jpace121.net /etc/nginx/sites-enabled/limbo.jpace121.net
I then restarted the nginx service (using sudo systemctl restart nginx) so the new config would take effect.
The config file above is setup to host files from /var/www/limbo.jpace121.net, so we need to create that directory (as root) and then change it’s permissions so we can upload files to it as the admin user.
sudo mkdir /var/www/limbo.jpace121.net
sudo chown -R admin:admin /var/www.jpace121.net
Step 3: Using certbot to get a cert from LetsEncrypt.
I use LetsEncrypt and certbot so I can ue https for all my self hosted sites, and so already have it installed on my Lightsail instance.
To add my new site, I ran:
sudo certbot certonly --webroot -w /var/www/limbo.jpace121.net -d limbo.jpace121.net
Once the command finishes, we should have certs where they are being looked for in our https server configuration, so we can open /etc/nginx/sites-available/limbo.jpace121.net, uncomment out the second server block, and then restart nginx.
Step 4: Build and Deploy the site
limbo.jpace121.net is written in TypeScript and uses vite and yarn for its build tool and package manager respectively.
As configured by default, running yarn build from the package will use vite to create a production build of the website, which is placed into the dist directory of the package.
Once we’ve built the package, to deploy it on the server we scp the files in dist to the /var/www/limbo.jpace.net directory on the server. (I.E. scp -r dist/. admin@vpn.jpace121.net:/var/www/limbo.jpace121.net/.). Once that’s complete, we should be abel to load the webpage locally and see that the contents have changed.
Further updates to the site should only require completing Step 3. To make that easier I’ve added the two commands required (one to build the project, and one to deploy it) to my justfile for my web project so I can call a single command and have the right thing happen.
Conclusion
Once the initial set up is done, actually deploying the site is fairly easy.
A lot of times for static sites, hobbyists use something like Github Pages because it is both easy and free. I don’t think the process is that much harder with my method, and I appreciate the extra control I have on what gets published when.