3.5 KiB
CLAUDE.md
Project overview
Server provisioning and app management for the hantim webserver. This repo
lives at /opt/hantim on the production server (Rocky Linux 9 on Vultr) and
manages Docker Compose configs, deploy scripts, nginx configs, and Gitea
Actions workflows.
Key files
scripts/bootstrap.sh-- First-time server setup (manual, uses Bitwarden)scripts/configure.sh-- Idempotent server config (firewall, certbot, start services; CI-safe)scripts/deploy.sh-- SSH-triggered deploy + cert issuance + provision (deploy-, cert-, provision commands)scripts/new-app.sh-- Single-command new static site (DNS + Gitea repo + cert + deploy + verify)scripts/new-service.sh-- Scaffold a new Docker Compose service (compose + workflow)docker/nginx/-- Reverse proxy (nginx:alpine + certbot on host)docker/<domain>/compose.yml-- Per-app compose files.gitea/workflows/deploy-<app>.yml-- Per-app deploy workflows.gitea/workflows/provision.yml-- Triggers configure.sh on setup changes
Conventions
- App name = domain (e.g.,
hcsuzuki.net) - Container name = domain with dots replaced by underscores (e.g.,
hcsuzuki_net) - Image =
git.timothykim.net/hantim/<domain>:latest - Cert name = config filename without
.conf(at/etc/letsencrypt/live/<name>/) - One domain per conf file -- deploy.sh derives cert name from filename
- All HTTP redirects to HTTPS; bare domain redirects to
www.<domain> - The
sharedDocker network is created by nginx compose and used by all apps
Secrets
Stored in Bitwarden (free tier), fetched via bw CLI:
hantim-ci-registry-push-- Secure Note (Gitea registry token)hantim-server-deploy-- SSH Key (deploy user key pair)hantim-new-app-script-- Secure Note (Gitea API token for creating repos)hantim-vultr-api-key-- Secure Note (Vultr API key for DNS management)argento-garage-- Secure Note (Garage rpc_secret, argento_node_id, S3 keys)
Gitea org-level (hantim) secrets/variables:
DEPLOY_HOST-- Variable (server IP)DEPLOY_SSH_KEY-- Secret (deploy SSH private key)CI_REGISTRY_TOKEN-- Secret (registry token)
Working with this repo
Adding a new static site
Run ./scripts/new-app.sh <domain> from dev machine. Handles everything:
DNS, Gitea repo, SSL cert, commit/push, build trigger, and verification.
See USECASES.md for full details.
Adding a new Docker service
Run ./scripts/new-service.sh <name> to scaffold the compose file and deploy
workflow, then edit the compose file and commit.
Editing scripts
All shell scripts use set -euo pipefail. Keep all steps idempotent.
configure.sh must be safe to re-run from CI.
Deploy flow
App repo push -> build.yml builds image, pushes to registry, SSHes to server
-> deploy.sh pulls repo, pulls image, restarts container.
Infrastructure push (this repo) -> deploy-<app>.yml triggers on path match
-> same deploy.sh flow. nginx deploys test config with nginx -t first.
Setup change push -> provision.yml triggers -> deploy.sh provision
-> configure.sh (firewall, certbot, start services).
Build and test
No build step. No tests. Verify changes by:
- Reading scripts and checking idempotency
- Walking through each use case in USECASES.md
- Cross-checking documentation (README.md, ARCHITECTURE.md, USECASES.md) against scripts
Commit style
- Short, lowercase commit messages (e.g., "add hcsuzuki.net", "fix deploy command")
- Do NOT include "Co-Authored-By" lines
- Commit only when explicitly asked