restructure docs: eliminate duplication across md files
This commit is contained in:
@@ -1,93 +1,44 @@
|
||||
# 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.
|
||||
Quick context for Claude Code. See README.md for full details, ARCHITECTURE.md
|
||||
for technical deep-dives, USECASES.md for expected behaviors.
|
||||
|
||||
## 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)
|
||||
- `tools/new-app.sh` -- Single-command new static site (DNS + Gitea repo + cert + deploy + verify)
|
||||
- `tools/new-app.sh` -- Single-command new static site (DNS + Gitea repo + cert + bucket + deploy + verify)
|
||||
- `tools/new-service.sh` -- Scaffold a new Docker Compose service (compose + workflow)
|
||||
- `tools/remove-app.sh` -- Remove a static site (local files + Gitea repo)
|
||||
- `docker/nginx/` -- Reverse proxy (nginx:alpine + certbot on host)
|
||||
- `docker/nginx/conf.d/` -- Per-app nginx server blocks
|
||||
- `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
|
||||
- `docker/garage/` -- Garage S3 object storage (Dockerfile, garage.toml, .env.keys)
|
||||
- `.gitea/workflows/` -- Per-app deploy workflows + provision.yml
|
||||
|
||||
## Conventions
|
||||
|
||||
- **App name = domain** (e.g., `example.com`)
|
||||
- **Container name** = domain with dots replaced by underscores (e.g., `example_com`)
|
||||
- **Image** = `git.timothykim.net/hantim/<domain>:latest`
|
||||
- **Cert name** = config filename without `.conf` (at `/etc/letsencrypt/live/<name>/`)
|
||||
- **Container name** = dots → underscores (e.g., `example_com`)
|
||||
- **One domain per conf file** -- deploy.sh derives cert name from filename
|
||||
- All HTTP redirects to HTTPS; bare domain redirects to `www.<domain>`
|
||||
- All HTTP → HTTPS; bare domain → `www.<domain>`
|
||||
- All shell scripts use `set -euo pipefail` and must be idempotent
|
||||
- The `shared` Docker network is created by nginx compose and used by all apps
|
||||
- Secrets are in Bitwarden Secrets Manager (see README.md for full list)
|
||||
- Service secrets use `.env.keys` files (see README.md)
|
||||
|
||||
## Secrets
|
||||
## Deploy flow
|
||||
|
||||
Bitwarden Secrets Manager (project: `hantim`, fetched via `bws` CLI):
|
||||
- `hantim-ci-registry-push` -- Gitea registry token (used by bootstrap.sh)
|
||||
- `hantim-deploy-ssh-private-key` -- deploy user SSH private key (used by new-app.sh)
|
||||
- `hantim-deploy-ssh-public-key` -- deploy user SSH public key (used by bootstrap.sh)
|
||||
- `hantim-new-app-script` -- Gitea API token for creating repos (used by new-app.sh)
|
||||
- `hantim-vultr-api-key` -- Vultr API key for DNS management (used by new-app.sh)
|
||||
- `hantim-garage-rpc-secret` -- Garage cluster RPC secret (used by deploy.sh)
|
||||
- `hantim-garage-argento-node-id` -- Argento's Garage node ID + address (used by deploy.sh)
|
||||
- `hantim-garage-admin-token` -- Garage admin API token (used by deploy.sh, new-app.sh)
|
||||
- `hantim-garage-media-key-id` -- S3 access key ID for media uploads (used by new-app.sh)
|
||||
- `hantim-garage-media-secret-key` -- S3 secret key for media uploads (used by aws CLI)
|
||||
|
||||
Machine accounts:
|
||||
- `hantim-server` -- access token stored at `/etc/bws-token` on hantim
|
||||
- `hantim-ci` -- access token stored as Gitea secret (reserved for future use)
|
||||
|
||||
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 `./tools/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 `./tools/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).
|
||||
- App repo push → `build.yml` → build/push image → SSH `deploy-<domain>` → deploy.sh
|
||||
- This repo push → `deploy-<app>.yml` (path match) → SSH `deploy-<app>` → deploy.sh
|
||||
- Setup change → `provision.yml` → SSH `provision` → configure.sh
|
||||
|
||||
## 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
|
||||
3. Cross-checking docs against scripts
|
||||
|
||||
## Commit style
|
||||
|
||||
|
||||
Reference in New Issue
Block a user