timothykim a3fb085fdb
Deploy nginx / deploy (push) Failing after 1s
Deploy timothykim.net / deploy (push) Failing after 1s
initial commit
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00
2026-03-12 21:16:59 -04:00

hantim-server

Server provisioning and app management for the hantim webserver. This repo lives at /opt 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 (routes to per-app deploy scripts)
  deploy-nginx.sh    # Deploy script for nginx
  deploy-timothykim.sh  # Deploy script for timothykim.net
  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:

dnf install -y git git-crypt
git clone <repo-url> /opt
git-crypt unlock /path/to/git-crypt-key
/opt/setup.sh

setup.sh installs Docker, creates a deploy user, sets up the shared Docker network, and starts all services. See the script for the full list of post-setup steps (registry login, Nginx Proxy Manager config, etc.).

How deploys work

Each app has three components:

  1. Deploy script (scripts/deploy-<app>.sh) -- pulls the latest repo changes, then runs docker compose pull && up -d for that app.
  2. 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.
  3. SSH dispatcher (scripts/deploy-dispatch.sh) -- the deploy user's authorized_keys is locked to this script via a command= directive. It reads SSH_ORIGINAL_COMMAND to route to the correct per-app deploy script.

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:

./scripts/new-app.sh <app-name>

This creates:

  • docker/<app-name>/compose.yml -- a starter compose file on the shared network
  • scripts/deploy-<app-name>.sh -- the deploy script
  • .gitea/workflows/deploy-<app-name>.yml -- the Gitea Actions workflow
  • A new case in scripts/deploy-dispatch.sh

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
S
Description
No description provided
Readme 500 KiB
Languages
Shell 65.2%
Python 33.5%
Assembly 0.5%
Dockerfile 0.4%
HTML 0.4%