# Monotrope Personal blog and server infrastructure for monotrope.au. ## Project Structure ``` monotrope/ site/ # Hugo site (content, templates, config) infra/ # Server setup scripts and config files deploy.sh # Build + rsync to production Makefile # Common tasks ``` ## Tech Stack - **Static site generator:** Hugo - **Web server:** Caddy (automatic HTTPS via Let's Encrypt) - **Hosting:** DigitalOcean droplet (Sydney region, Ubuntu 24.04 LTS) - **Deployment:** `hugo build` then `rsync` to server - **Future services:** Docker Compose for anything beyond the blog ## Setup Tasks ### 1. Initialise the repo - Create the directory structure above - `git init` with a sensible `.gitignore` (Hugo output dir `public/`, `.env`, etc.) - Initialise a new Hugo site inside `site/` - Use a minimal theme or no theme — we'll build templates from scratch later - Hugo config should set `baseURL = "https://monotrope.au"` ### 2. Create a minimal Hugo site - A single layout (`layouts/_default/baseof.html`, `single.html`, `list.html`) - Minimal, clean CSS — no framework. Readable prose typography, dark mode support via `prefers-color-scheme` - A sample first post in `site/content/posts/` so we can test the build - RSS feed enabled (Hugo does this by default) - No JavaScript unless strictly necessary ### 3. Server provisioning script Create `infra/setup.sh` — a bash script intended to be run once on a fresh Ubuntu 24.04 droplet via SSH. It should: - Update packages - Install Caddy via the official apt repo - Create a `www` user with no login shell to own the site files - Create `/var/www/monotrope` owned by `www` - Install a Caddyfile at `/etc/caddy/Caddyfile` that: - Serves `monotrope.au` from `/var/www/monotrope` - Enables gzip/zstd compression - Sets sensible cache headers for static assets - Handles `www.monotrope.au` redirect to apex - Enable and start the Caddy service - Set up UFW: allow SSH, HTTP, HTTPS, deny everything else - Install Docker and Docker Compose (for future use, not needed yet) - Create a deploy user with SSH key auth and permission to write to `/var/www/monotrope` Also create `infra/Caddyfile` as a standalone config file that the setup script copies into place. ### 4. Deploy script Create `deploy.sh` at the repo root: - Run `hugo --minify` in `site/` - `rsync -avz --delete site/public/ deploy@:/var/www/monotrope/` - Print the URL on success The droplet IP should come from an environment variable `MONOTROPE_HOST` or a `.env` file (not committed). ### 5. Makefile Targets: - `make build` — build the site locally - `make serve` — `hugo server` for local dev with live reload - `make deploy` — run `deploy.sh` - `make ssh` — SSH into the droplet as the deploy user - `make setup` — run the provisioning script on a fresh droplet ## Conventions - All shell scripts should use `set -euo pipefail` - Prefer clarity over cleverness in all scripts - No unnecessary dependencies — this should stay simple - Australian English in all content and comments - Markdown content lives in `site/content/`; one subdirectory per content type (e.g. `posts/`, `pages/`) ## DNS The user will configure DNS separately via their registrar. The server expects: - `monotrope.au` → droplet IP (A record) - `www.monotrope.au` → droplet IP (A record) Caddy will handle certificate provisioning automatically once DNS is pointed. ## What This Is Not - No CI/CD pipeline — deploy is manual via `make deploy` - No containerisation of the blog itself — it's static files - No database - No analytics (for now) - No comments system (for now)