Files
hantim-server/CLAUDE.md
T
timothykim 919c5353bc
Provision server / provision (push) Failing after 2s
split setup.sh into bootstrap.sh and configure.sh
bootstrap.sh handles first-time setup (manual, Bitwarden).
configure.sh handles idempotent config (CI-safe).
Add provision workflow, deploy-garage workflow, new-service.sh.
Remove git-crypt references and empty .gitattributes.
2026-03-18 14:51:19 -04:00

3.4 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 = domain (at /etc/letsencrypt/live/<domain>/)
  • All HTTP redirects to HTTPS; bare domain redirects to www.<domain>
  • The shared Docker 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:

  1. Reading scripts and checking idempotency
  2. Walking through each use case in USECASES.md
  3. 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