How this site is built
A tour of the stack behind jackneff.dev — Flask and HTMX on a plain Linux box, with deploys that happen on git push.
September 3, 2026
This site is deliberately small. No framework-of-frameworks, no build step, no container orchestration. One virtualenv, one systemd unit, one nginx vhost.
The app
Flask with the app-factory pattern, Flask-SQLAlchemy for the handful of project rows, and HTMX for the tag filtering on the front page — the server returns an HTML fragment and HTMX swaps it in. The blog you're reading is just Markdown files with front matter, parsed at request time.
def create_app(config_class: type = Config) -> Flask:
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
app.register_blueprint(main)
return app
Pico.css and htmx are vendored into static/ — no CDN at runtime. Fonts are the
one exception.
The box
A 1 GB DigitalOcean droplet running Ubuntu. gunicorn binds a Unix socket;
systemd owns the process and restarts it on failure; nginx terminates TLS and
proxies everything that isn't /static/.
location / {
proxy_pass http://unix:/run/portfolio/portfolio.sock;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
Let's Encrypt for the certificate, Cloudflare in front for DNS and caching.
Deploys
There's no CI. Deploying is git push to a bare repo on the server, and a
post-receive hook does the rest:
git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" checkout -f "$BRANCH"
"$VENV/bin/pip" install -r requirements.txt --quiet
sudo systemctl restart portfolio
curl -fsS --unix-socket /run/portfolio/portfolio.sock http://localhost/healthz
If the health check fails, the push fails, and I know before I close the terminal.
That's the whole thing. It's boring on purpose.