This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user