2026-10-13 23:11:40 +02:00
|
|
|
# The Forgejo Actions runner of this repository's CI, on learn.halkyon.eu's server. Installed as
|
ci: check every push on sahaquiel and deploy a green main
Pushes to main were deployed by hand. Now Forgejo Actions runs tool/check.sh on every
push, and a green main deploys learn.halkyon.eu by itself.
The runner (forgejo-runner v13.1.0) runs on sahaquiel as the unprivileged user `runner`,
with jobs directly on the host: containers would take Docker access, which is root on the
production server, and Forgejo warns that host jobs have no isolation from the runner's
user. So its systemd unit (deploy/runner/forgejo-runner.service) provides it: /home and
the Docker socket invisible, Docker's container networks unreachable, no capabilities,
two cores and 3 GB at most, lowest priority. It is registered to this repository only,
with the UUID and token of Forgejo's "Create new runner" (the old `register` is
deprecated); the token reaches it as a systemd credential. The configuration
(deploy/runner/config.yml) was dry-run against v13.1.0, the unit rates 1.8 in
`systemd-analyze security`. CI runs on pushes only: a pull request from a fork would run
its code on the production server.
The deploy job calls deploy/redeploy.sh as `deploy`, through a key that authorized_keys
pins to that script and to connections from sahaquiel itself. The script deploys the
commit CI checked while it is still main's tip, as a fast-forward, only if every new
commit is signed by a key in deploy/allowed-signers (as the deployed checkout lists
them), after dumping the database (the last ten are kept), and fails unless the server
answers afterwards; a failure puts the checkout back. Tested against the local stack:
refusals of a malformed argument, a stale commit, a forged unsigned commit and a
non-fast-forward, a real deploy with its dump, a repeat, and a failed build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-09-30 21:49:04 +02:00
|
|
|
# /etc/forgejo-runner/config.yml, read by forgejo-runner.service (next to this file).
|
|
|
|
|
# Written for forgejo-runner v13.1.0; its full reference: `forgejo-runner generate-config`.
|
|
|
|
|
#
|
|
|
|
|
# Jobs run directly on the host as the unprivileged user `runner`, never in containers:
|
|
|
|
|
# running containers would take Docker access, which is root on the production server.
|
|
|
|
|
# The systemd unit keeps the jobs away from production.
|
|
|
|
|
|
|
|
|
|
log:
|
|
|
|
|
level: info
|
|
|
|
|
job_level: info
|
|
|
|
|
|
|
|
|
|
runner:
|
|
|
|
|
# One job at a time: CI shares the machine with the instance.
|
|
|
|
|
capacity: 1
|
|
|
|
|
timeout: 1h
|
|
|
|
|
shutdown_timeout: 10m
|
|
|
|
|
fetch_timeout: 30s
|
2026-10-13 23:11:40 +02:00
|
|
|
# How often to ask Forgejo for work. The default (2 s) is needless load on
|
|
|
|
|
# code.halkyon.app's server, a one-core one.
|
ci: check every push on sahaquiel and deploy a green main
Pushes to main were deployed by hand. Now Forgejo Actions runs tool/check.sh on every
push, and a green main deploys learn.halkyon.eu by itself.
The runner (forgejo-runner v13.1.0) runs on sahaquiel as the unprivileged user `runner`,
with jobs directly on the host: containers would take Docker access, which is root on the
production server, and Forgejo warns that host jobs have no isolation from the runner's
user. So its systemd unit (deploy/runner/forgejo-runner.service) provides it: /home and
the Docker socket invisible, Docker's container networks unreachable, no capabilities,
two cores and 3 GB at most, lowest priority. It is registered to this repository only,
with the UUID and token of Forgejo's "Create new runner" (the old `register` is
deprecated); the token reaches it as a systemd credential. The configuration
(deploy/runner/config.yml) was dry-run against v13.1.0, the unit rates 1.8 in
`systemd-analyze security`. CI runs on pushes only: a pull request from a fork would run
its code on the production server.
The deploy job calls deploy/redeploy.sh as `deploy`, through a key that authorized_keys
pins to that script and to connections from sahaquiel itself. The script deploys the
commit CI checked while it is still main's tip, as a fast-forward, only if every new
commit is signed by a key in deploy/allowed-signers (as the deployed checkout lists
them), after dumping the database (the last ten are kept), and fails unless the server
answers afterwards; a failure puts the checkout back. Tested against the local stack:
refusals of a malformed argument, a stale commit, a forged unsigned commit and a
non-fast-forward, a real deploy with its dump, a repeat, and a failed build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-09-30 21:49:04 +02:00
|
|
|
fetch_interval: 10s
|
|
|
|
|
report_interval: 1s
|
2026-10-13 23:11:40 +02:00
|
|
|
# `runs-on: instance` in a workflow means: here, on the instance's server, on the host.
|
|
|
|
|
labels: ["instance:host"]
|
ci: check every push on sahaquiel and deploy a green main
Pushes to main were deployed by hand. Now Forgejo Actions runs tool/check.sh on every
push, and a green main deploys learn.halkyon.eu by itself.
The runner (forgejo-runner v13.1.0) runs on sahaquiel as the unprivileged user `runner`,
with jobs directly on the host: containers would take Docker access, which is root on the
production server, and Forgejo warns that host jobs have no isolation from the runner's
user. So its systemd unit (deploy/runner/forgejo-runner.service) provides it: /home and
the Docker socket invisible, Docker's container networks unreachable, no capabilities,
two cores and 3 GB at most, lowest priority. It is registered to this repository only,
with the UUID and token of Forgejo's "Create new runner" (the old `register` is
deprecated); the token reaches it as a systemd credential. The configuration
(deploy/runner/config.yml) was dry-run against v13.1.0, the unit rates 1.8 in
`systemd-analyze security`. CI runs on pushes only: a pull request from a fork would run
its code on the production server.
The deploy job calls deploy/redeploy.sh as `deploy`, through a key that authorized_keys
pins to that script and to connections from sahaquiel itself. The script deploys the
commit CI checked while it is still main's tip, as a fast-forward, only if every new
commit is signed by a key in deploy/allowed-signers (as the deployed checkout lists
them), after dumping the database (the last ten are kept), and fails unless the server
answers afterwards; a failure puts the checkout back. Tested against the local stack:
refusals of a malformed argument, a stale commit, a forged unsigned commit and a
non-fast-forward, a real deploy with its dump, a repeat, and a failed build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-09-30 21:49:04 +02:00
|
|
|
|
|
|
|
|
cache:
|
|
|
|
|
# No cache server (it would listen on a port of its own); the SDKs and package
|
|
|
|
|
# caches of host jobs stay in the runner's home between jobs anyway.
|
|
|
|
|
enabled: false
|
|
|
|
|
|
|
|
|
|
container:
|
|
|
|
|
# Never talk to Docker.
|
|
|
|
|
docker_host: "-"
|
|
|
|
|
|
|
|
|
|
host:
|
|
|
|
|
workdir_parent: /var/lib/forgejo-runner/work
|
|
|
|
|
|
|
|
|
|
server:
|
|
|
|
|
connections:
|
|
|
|
|
code.halkyon.app:
|
|
|
|
|
url: https://code.halkyon.app/
|
|
|
|
|
# From the repository's Settings → Actions → Runners → Create new runner. Not a
|
|
|
|
|
# secret; the installation replaces the placeholder.
|
|
|
|
|
uuid: RUNNER_UUID
|
|
|
|
|
# The token is kept in /etc/forgejo-runner/token (root only) and handed over by
|
|
|
|
|
# systemd (LoadCredential in the unit).
|
|
|
|
|
token_url: file:$CREDENTIALS_DIRECTORY/token
|