Initial commit: Hugo site with Caddy infra and deploy tooling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Louis Simoneau
2026-04-08 19:45:03 +10:00
commit b090231557
14 changed files with 770 additions and 0 deletions

24
infra/Caddyfile Normal file
View File

@@ -0,0 +1,24 @@
monotrope.au {
root * /var/www/monotrope
file_server
# Compression
encode zstd gzip
# Cache headers for static assets
@static {
path *.css *.js *.ico *.gif *.jpg *.jpeg *.png *.webp *.svg *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
# HTML and RSS — revalidate each time
@html {
path *.html / /posts/ /posts/*
}
header @html Cache-Control "public, max-age=0, must-revalidate"
}
# Redirect www to apex
www.monotrope.au {
redir https://monotrope.au{uri} permanent
}

188
infra/ansible/playbook.yml Normal file
View File

@@ -0,0 +1,188 @@
---
- name: Provision monotrope.au server
hosts: all
become: true
vars:
site_dir: /var/www/monotrope
deploy_user: deploy
deploy_pubkey: "{{ lookup('file', lookup('env', 'HOME') + '/.ssh/id_ed25519.pub') }}"
tasks:
# ── System ──────────────────────────────────────────────────────────────
- name: Update apt cache and upgrade packages
apt:
update_cache: true
upgrade: dist
cache_valid_time: 3600
- name: Install common dependencies
apt:
name:
- debian-keyring
- debian-archive-keyring
- apt-transport-https
- curl
- ufw
state: present
# ── Caddy ───────────────────────────────────────────────────────────────
- name: Add Caddy GPG key
shell: |
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
args:
creates: /usr/share/keyrings/caddy-stable-archive-keyring.gpg
- name: Add Caddy apt repository
shell: |
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
args:
creates: /etc/apt/sources.list.d/caddy-stable.list
- name: Install Caddy
apt:
name: caddy
state: present
update_cache: true
- name: Install Caddyfile
copy:
src: ../Caddyfile
dest: /etc/caddy/Caddyfile
owner: root
group: caddy
mode: '0640'
notify: Restart Caddy
- name: Enable and start Caddy
systemd:
name: caddy
enabled: true
state: started
# ── Site directory ───────────────────────────────────────────────────────
- name: Create www system user
user:
name: www
system: true
create_home: false
shell: /usr/sbin/nologin
state: present
# ── UFW ─────────────────────────────────────────────────────────────────
- name: Set UFW default incoming policy to deny
ufw:
default: deny
direction: incoming
- name: Set UFW default outgoing policy to allow
ufw:
default: allow
direction: outgoing
- name: Allow SSH
ufw:
rule: allow
name: OpenSSH
- name: Allow HTTP
ufw:
rule: allow
port: '80'
proto: tcp
- name: Allow HTTPS
ufw:
rule: allow
port: '443'
proto: tcp
- name: Enable UFW
ufw:
state: enabled
# ── Docker ──────────────────────────────────────────────────────────────
- name: Create Docker keyring directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Add Docker GPG key
shell: |
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
args:
creates: /etc/apt/keyrings/docker.gpg
- name: Add Docker apt repository
shell: |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list
args:
creates: /etc/apt/sources.list.d/docker.list
- name: Install Docker
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: present
update_cache: true
- name: Enable Docker
systemd:
name: docker
enabled: true
state: started
# ── Deploy user ──────────────────────────────────────────────────────────
- name: Create deploy user
user:
name: "{{ deploy_user }}"
create_home: true
shell: /bin/bash
state: present
- name: Set up deploy user SSH directory
file:
path: "/home/{{ deploy_user }}/.ssh"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0700'
- name: Install deploy user SSH public key
ansible.posix.authorized_key:
user: "{{ deploy_user }}"
key: "{{ deploy_pubkey }}"
state: present
- name: Create site directory
file:
path: "{{ site_dir }}"
state: directory
owner: "{{ deploy_user }}"
group: www
mode: '0775'
handlers:
- name: Restart Caddy
systemd:
name: caddy
state: restarted

97
infra/setup.sh Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env bash
set -euo pipefail
# setup.sh — Provision a fresh Ubuntu 24.04 droplet for monotrope.au
# Run as root via: ssh root@<DROPLET_IP> 'bash -s' < infra/setup.sh
DEPLOY_USER="deploy"
SITE_DIR="/var/www/monotrope"
DEPLOY_PUBKEY="${DEPLOY_PUBKEY:-}" # Set this env var before running, or edit below
echo "==> Updating packages"
apt-get update -y
apt-get upgrade -y
# ── Caddy ─────────────────────────────────────────────────────────────────
echo "==> Installing Caddy"
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
apt-get update -y
apt-get install -y caddy
# ── Site directory ─────────────────────────────────────────────────────────
echo "==> Creating www user and site directory"
id -u www &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin www
mkdir -p "$SITE_DIR"
chown www:www "$SITE_DIR"
chmod 755 "$SITE_DIR"
# ── Caddyfile ──────────────────────────────────────────────────────────────
echo "==> Installing Caddyfile"
cp "$(dirname "$0")/Caddyfile" /etc/caddy/Caddyfile
chown root:caddy /etc/caddy/Caddyfile
chmod 640 /etc/caddy/Caddyfile
systemctl enable caddy
systemctl restart caddy
# ── UFW ────────────────────────────────────────────────────────────────────
echo "==> Configuring UFW"
apt-get install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow http
ufw allow https
ufw --force enable
# ── Docker ────────────────────────────────────────────────────────────────
echo "==> Installing Docker"
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list
apt-get update -y
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable docker
# ── Deploy user ───────────────────────────────────────────────────────────
echo "==> Creating deploy user"
id -u "$DEPLOY_USER" &>/dev/null || useradd --create-home --shell /bin/bash "$DEPLOY_USER"
# Give deploy user write access to the site directory
chown -R "$DEPLOY_USER":www "$SITE_DIR"
chmod 775 "$SITE_DIR"
# Set up SSH key auth
DEPLOY_HOME="/home/$DEPLOY_USER"
mkdir -p "$DEPLOY_HOME/.ssh"
chmod 700 "$DEPLOY_HOME/.ssh"
touch "$DEPLOY_HOME/.ssh/authorized_keys"
chmod 600 "$DEPLOY_HOME/.ssh/authorized_keys"
chown -R "$DEPLOY_USER":"$DEPLOY_USER" "$DEPLOY_HOME/.ssh"
if [[ -n "$DEPLOY_PUBKEY" ]]; then
echo "$DEPLOY_PUBKEY" >> "$DEPLOY_HOME/.ssh/authorized_keys"
echo "==> Deploy public key installed"
else
echo "WARNING: DEPLOY_PUBKEY not set. Add your public key to $DEPLOY_HOME/.ssh/authorized_keys manually."
fi
echo ""
echo "==> Done. Checklist:"
echo " - Point DNS A records for monotrope.au and www.monotrope.au to this server's IP"
echo " - If DEPLOY_PUBKEY was not set, add your key to $DEPLOY_HOME/.ssh/authorized_keys"
echo " - Run 'make deploy' from your local machine to push the site"