Files
hantim-server/README.md
T
timothykim 7d5f0920b7 replace per-app deploy scripts with generic deploy.sh
Dispatch now validates the command format and routes to a single
deploy.sh that handles any app. This fixes first-deploy failures
for new apps (dispatch no longer needs a static case list) and
simplifies new-app.sh (no deploy script or dispatch update needed).

Also adds input validation to new-app.sh, set -euo pipefail to
deploy scripts, and dnf module reset before nodejs install.
2026-03-13 17:00:59 -04:00

93 lines
3.1 KiB
Markdown

# hantim-server
Server provisioning and app management for the hantim webserver. This repo
lives at `/opt/hantim` on the server and contains Docker Compose configs, deploy
scripts, and Gitea Actions workflows for each app.
## Repo structure
```
docker/ # One directory per app, each with a compose.yml
nginx/ # Nginx Proxy Manager (reverse proxy + TLS)
timothykim.net/ # timothykim.net static site
scripts/
deploy-dispatch.sh # SSH command dispatcher (validates and routes deploy commands)
deploy.sh # Generic deploy script (git pull + docker compose up)
new-app.sh # Scaffolding script to add a new app
setup.sh # One-time server provisioning script
.gitea/workflows/ # Per-app deploy workflows triggered by path changes
```
## Initial server setup
On a fresh Rocky Linux 9 (or compatible) install:
```bash
dnf install -y git
git clone https://git.timothykim.net/timothykim/hantim-server.git /opt/hantim
bash /opt/hantim/setup.sh
```
`setup.sh` handles everything else: installs git-crypt and the Bitwarden CLI,
fetches the git-crypt key from your Bitwarden vault (stored as a base64-encoded
secure note named `hantim-git-crypt-key`), unlocks the repo, installs Docker,
creates the `deploy` user, and starts all services.
To save the git-crypt key to Bitwarden (one-time, from your dev machine):
```bash
base64 /path/to/git-crypt-key
# Save the output as a Bitwarden secure note named "hantim-git-crypt-key"
```
## How deploys work
Each app has two components:
1. **Gitea Actions workflow** (`.gitea/workflows/deploy-<app>.yml`) -- triggers
on pushes to `main` when files under `docker/<app>/` change. SSHes into the
server as the `deploy` user to trigger the deploy.
2. **SSH dispatcher** (`scripts/deploy-dispatch.sh`) -- the `deploy` user's
`authorized_keys` is locked to this script via a `command=` directive. It
validates the command and runs `scripts/deploy.sh`, which pulls the latest
repo changes and runs `docker compose pull && up -d` for that app.
This means:
- Pushing a change to `docker/nginx/compose.yml` only deploys nginx.
- Pushing a change to `scripts/` or `setup.sh` does not trigger any deploy.
- Each app deploys independently.
## Adding a new app
Run the scaffolding script:
```bash
./scripts/new-app.sh <app-name>
```
This creates:
- `docker/<app-name>/compose.yml` -- a starter compose file on the `shared`
network
- `.gitea/workflows/deploy-<app-name>.yml` -- the Gitea Actions workflow
After running the script:
1. Edit `docker/<app-name>/compose.yml` to fit your app (image, ports,
volumes, environment variables, etc.).
2. Commit and push to `main`.
3. Configure the proxy host in Nginx Proxy Manager to route traffic to the new
service.
## Secrets
Nginx Proxy Manager certs and Let's Encrypt account keys are encrypted with
git-crypt (see `.gitattributes`). You need the git-crypt key to unlock them.
The following secrets must be configured in the Gitea repo settings for
deploys to work:
- `DEPLOY_HOST` -- the server's IP or hostname
- `DEPLOY_KEY` -- the SSH private key for the `deploy` user