5c38b0631a
- nginx:alpine replaces nginx-proxy-manager - certbot on host with standalone issuance and auto-renewal - per-site nginx configs in conf.d/ (HTTP->HTTPS, bare->www) - container names use underscores (timothykim_net) - setup.sh: automated cert issuance, dynamic app startup - deploy.sh: nginx -t guard, graceful image-not-found - new-app.sh: Gitea API repo creation, nginx conf generation - add ARCHITECTURE.md, USECASES.md, CLAUDE.md - remove old NPM data/certs from tracking
118 lines
3.9 KiB
Markdown
118 lines
3.9 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, nginx configs, and Gitea Actions workflows for each app.
|
|
|
|
## Repo structure
|
|
|
|
```
|
|
docker/
|
|
nginx/ # Reverse proxy (nginx:alpine) + SSL config
|
|
nginx.conf # Main nginx config
|
|
conf.d/ # Per-app server blocks (e.g. timothykim.net.conf)
|
|
compose.yml
|
|
timothykim.net/ # timothykim.net static site
|
|
compose.yml
|
|
scripts/
|
|
deploy.sh # Deploy script (validates command, git pull, docker compose up)
|
|
new-app.sh # Scaffolding script to add a new app
|
|
setup.sh # Server provisioning script (idempotent)
|
|
.gitea/workflows/ # Per-app deploy workflows triggered by path changes
|
|
```
|
|
|
|
## Provisioning a new server
|
|
|
|
On a fresh Rocky Linux 9 install:
|
|
|
|
```bash
|
|
dnf install -y git
|
|
git clone https://git.timothykim.net/hantim/hantim-server.git /opt/hantim
|
|
bash /opt/hantim/setup.sh
|
|
```
|
|
|
|
`setup.sh` is fully automated and idempotent. It:
|
|
|
|
1. Installs system dependencies (git-crypt, jq, certbot, Node.js 20, Docker)
|
|
2. Installs and authenticates the Bitwarden CLI
|
|
3. Unlocks git-crypt using a key stored in Bitwarden
|
|
4. Fetches the Docker registry token and deploy SSH public key from Bitwarden
|
|
5. Logs into the Gitea Docker registry
|
|
6. Creates the `deploy` user with restricted SSH access and sudo
|
|
7. Issues SSL certificates via certbot for all configured domains
|
|
8. Starts all services (nginx first, then all apps)
|
|
|
|
**Prerequisites**: DNS for all configured domains must point to the server
|
|
before running setup.
|
|
|
|
## Adding a new app
|
|
|
|
```bash
|
|
./scripts/new-app.sh <domain>
|
|
```
|
|
|
|
Example: `./scripts/new-app.sh hcsuzuki.net`
|
|
|
|
This creates:
|
|
|
|
- A Gitea repo (`hantim/<domain>`) from the `static-site-template`
|
|
- `docker/<domain>/compose.yml` -- app compose file
|
|
- `.gitea/workflows/deploy-<domain>.yml` -- deploy workflow
|
|
- `docker/nginx/conf.d/<domain>.conf` -- nginx proxy config (HTTP->HTTPS,
|
|
bare domain->www)
|
|
|
|
After running the script:
|
|
|
|
1. Issue the SSL cert on the server (**before** pushing):
|
|
```bash
|
|
docker stop nginx
|
|
certbot certonly --standalone --non-interactive --agree-tos \
|
|
--register-unsafely-without-email --cert-name <domain> \
|
|
-d <domain> -d www.<domain>
|
|
docker start nginx
|
|
```
|
|
2. Commit and push this repo to deploy
|
|
3. Clone the new app repo, customize it, and push to build/deploy
|
|
|
|
## Deploying changes
|
|
|
|
**App code change** (push to an app repo like `timothykim.net`):
|
|
- The app's `build.yml` builds the Docker image, pushes to the registry, and
|
|
SSHes into the server to trigger a deploy
|
|
|
|
**Compose or nginx config change** (push to this repo):
|
|
- Gitea Actions workflows trigger based on which `docker/<app>/` paths changed
|
|
- `deploy.sh` pulls the latest code and runs `docker compose up -d`
|
|
- For nginx deploys, the config is tested before applying to prevent downtime
|
|
|
|
## Restoring from backup
|
|
|
|
Run the same three commands as provisioning. `setup.sh` is idempotent:
|
|
- Existing packages are skipped
|
|
- Existing certs are skipped (or re-issued if the server is new)
|
|
- All services are started
|
|
|
|
## Secrets
|
|
|
|
The following are stored in Bitwarden and fetched automatically by `setup.sh`:
|
|
|
|
| Bitwarden item | Type | Purpose |
|
|
|---|---|---|
|
|
| `hantim-git-crypt-key` | Secure Note | git-crypt symmetric key (base64) |
|
|
| `hantim-ci-registry-push` | Secure Note | Gitea token for Docker registry |
|
|
| `hantim-server-deploy` | SSH Key | Deploy user's SSH key |
|
|
|
|
The following are configured in the `hantim` Gitea org settings:
|
|
|
|
| Name | Type | Purpose |
|
|
|---|---|---|
|
|
| `DEPLOY_HOST` | Variable | Server IP or hostname |
|
|
| `DEPLOY_SSH_KEY` | Secret | SSH private key for the deploy user |
|
|
| `CI_REGISTRY_TOKEN` | Secret | Gitea token for Docker registry login |
|
|
|
|
The following is stored in Bitwarden and used by `new-app.sh`:
|
|
|
|
| Bitwarden item | Type | Purpose |
|
|
|---|---|---|
|
|
| `hantim-new-app-script` | Secure Note | Gitea API token for creating repos |
|