deployed the website
finally did it. bought a $4/mo droplet on digitalocean and got the site live at jhjhjljl.com.
went with debian, toronto region. no docker, no fancy setup — just ssh'd in, cloned the repo, installed dependencies, and got it running. learned a lot more doing it that way than i would have pulling a pre-configured image.
(to be honest, the cheapest plan only had 512mb of ram, so running docker would have been extremely tight. i had no choice but to optimize it to use as few system resources as possible.)
first thing after ssh'ing in was updating packages and installing everything needed:
apt update && apt upgrade -y
apt install -y git nginx python3-pip certbot python3-certbot-nginx
cloned the repo and installed python dependencies:
git clone https://github.com/jhjhjljl/website.git /var/www/html/website
pip3 install -r requirements.txt --break-system-packages
--break-system-packages bypasses debian's protection on system python. fine on a single-purpose server.
for nginx, created the config, removed the default site, then symlinked to enable it:
nano /etc/nginx/sites-available/website
rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/website /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx
sites-available stores all configs. sites-enabled is what nginx actually loads — symlinks point to sites-available. -t tests the config syntax before applying.
ssl was one command:
certbot --nginx -d jhjhjljl.com -d www.jhjhjljl.com
gets a free cert from let's encrypt, updates the nginx config automatically, and sets up a cron job to auto-renew every 90 days.
for systemd, created /etc/systemd/system/website.service:
[Unit]
Description=Justin Lee Website
After=network.target
[Service]
WorkingDirectory=/var/www/html/website/app
ExecStart=uvicorn main:app --host 127.0.0.1 --port 8000
Restart=always
[Install]
WantedBy=multi-user.target
then:
systemctl daemon-reload
systemctl enable website
systemctl start website
enable creates a symlink so it starts on boot. Restart=always means if uvicorn crashes, systemd brings it back up automatically.
the stack is pretty simple. uvicorn runs the fastapi app on 127.0.0.1:8000, nginx sits in front of it and handles https and static files. certbot set up the ssl cert in like one command and auto-renews every 90 days. systemd keeps uvicorn alive so if it crashes it just restarts itself.
i've set set up the nginx config so it serves static files straight from disk without touching python. clean separation.
for dns, bought jhjhjljl.com on porkbun ($14, same for renewal) and added two a records pointing to the droplet ip (68.183.193.100):
@— the root domain (jhjhjljl.com)www— the www subdomain
hit a snag where porkbun had a default cname record on @ that conflicted with the a record. had to delete it first before the a record would save. once that was cleared it was fine.
dns propagated faster than i expected — within a few minutes it was resolving. thought it would take hours.
glad i did it the hard way. going through every step manually — nginx config, symlinks, systemd unit files — means i actually understand what's running and why. would've had no idea with docker.
on average, it consumes 0.3% cpu, and 40% ram. so we are good for now. i'm glad i cheaped out and went with the cheapest plan.
i will set up post hook later.