Automate production deployment on main pushes
Deploy production / deploy (push) Successful in 3s

This commit is contained in:
Labyricorn Deployment
2026-08-11 20:44:14 -07:00
parent 089589f8c4
commit 5b17b52e3f
2 changed files with 85 additions and 12 deletions
+27
View File
@@ -0,0 +1,27 @@
name: Deploy production
on:
push:
branches:
- main
concurrency:
group: labyricorn-production
cancel-in-progress: false
jobs:
deploy:
runs-on: labyricorn-deploy
timeout-minutes: 10
steps:
- name: Build and activate current main
run: sudo -n /usr/local/bin/deploy-labyricorn
- name: Verify the deployed revision and origin
run: |
deployed_revision="$(cat /srv/labyricorn/current/.labyricorn-commit)"
test "$deployed_revision" = "$GITHUB_SHA"
curl --fail --silent --show-error \
-H 'Host: www.labyricorn.com' \
-H 'X-Forwarded-Proto: https' \
http://127.0.0.1/ >/dev/null
+58 -12
View File
@@ -71,8 +71,9 @@ ignored and must not be committed.
## Routine content workflow ## Routine content workflow
The preferred workflow is to edit in a normal Git checkout, review the changes, Edit in a normal Git checkout, review the changes, and push them to `main`.
push them to `main`, and then deploy on the production host. A successful push triggers the repository's Gitea Action, which builds and
atomically activates that exact revision on the production host.
```bash ```bash
git switch main git switch main
@@ -87,7 +88,8 @@ git commit -m "Describe the site change"
git push origin main git push origin main
``` ```
Then deploy on `ubuntu2-47`: Watch the run under **Actions** in Gitea. Manual deployment remains available
for recovery or controlled operations:
```bash ```bash
sudo deploy-labyricorn sudo deploy-labyricorn
@@ -512,17 +514,61 @@ The first origin request should redirect; the simulated Cloudflare HTTPS request
should return the site. A different result indicates a proxy/header or nginx should return the site. A different result indicates a proxy/header or nginx
configuration problem. configuration problem.
## Future automatic deployment ## Automatic deployment
Manual deployment is complete and remains the supported path. Automatic Pushes to `main` automatically deploy through Gitea Actions. The workflow is
deployment is not configured. versioned with the site at `.gitea/workflows/deploy.yml` and has one job:
The preferred future design is a Gitea Action triggered only by pushes to 1. Run on the repository-scoped runner labelled `labyricorn-deploy`.
`main`, invoking `deploy-labyricorn` through a dedicated, narrowly restricted 2. Execute the existing root-owned `deploy-labyricorn` command.
SSH identity. A webhook receiver is acceptable only if it authenticates a 3. Confirm `/srv/labyricorn/current/.labyricorn-commit` equals the pushed commit.
secret, verifies the repository and branch, never executes payload text, and 4. Request the site through nginx on the local origin and fail if it is unhealthy.
runs with minimal privileges. Never expose a general shell endpoint or an
unauthenticated HTTP deployment URL. The action intentionally does not check out the repository into its own
workspace. The deployment script fetches `origin/main` using the dedicated
`labyricorn-deploy` account, validates a clean checkout, builds a new release,
and atomically changes the `current` symlink. Concurrent action runs share the
`labyricorn-production` concurrency group, and the deployment script also uses
a filesystem lock.
### Runner installation
The production host runs official Gitea Runner 3.0.0 directly on Linux; Docker
is not installed or required for this workflow.
| Item | Value |
|---|---|
| systemd unit | `gitea-runner.service` |
| service account | `gitea-runner` |
| runner name | `labyricorn-production` |
| registration scope | `Labyricorn/labyricorn-site` repository |
| execution label | `labyricorn-deploy:host` |
| runner binary | `/usr/local/bin/gitea-runner` |
| runner configuration | `/etc/gitea-runner/config.yaml` |
| registration state | `/var/lib/gitea-runner/.runner` |
| job workspace | `/var/lib/gitea-runner/work` |
| sudo policy | `/etc/sudoers.d/gitea-runner-labyricorn` |
The runner account has no general administrative access. Its sudo policy allows
only this exact command without a password:
```text
/usr/local/bin/deploy-labyricorn
```
Useful checks:
```bash
systemctl status gitea-runner
journalctl -u gitea-runner -n 100 --no-pager
sudo -l -U gitea-runner
```
If the runner must be replaced, delete or disable it in **Repository Settings →
Actions → Runners**, generate a fresh repository registration token, and
register the replacement. Registration tokens and `.runner` contents are
credentials: never commit or print them. A push can still be deployed manually
with `sudo deploy-labyricorn` while the runner is unavailable.
## Change-control checklist ## Change-control checklist