4 Commits

Author SHA1 Message Date
2e228f137b runner: drop the deleted .example file 2026-05-18 20:49:53 +00:00
3da73147dc runner: Caddy service for cache HTTPS frontend (router-PAT-friendly ports) 2026-05-18 20:49:31 +00:00
fcecc1e5b0 runner: Caddyfile for cache HTTPS frontend + README 2026-05-18 20:34:02 +00:00
bbae941a36 publish: greeter 0.1.1 (#5)
Co-authored-by: Amadey Vorontsov <vorontsov@amadey.xyz>
Co-committed-by: Amadey Vorontsov <vorontsov@amadey.xyz>
2026-05-18 20:07:54 +00:00
5 changed files with 123 additions and 22 deletions

View File

@@ -0,0 +1,17 @@
schema = 1
name = "greeter"
version = "0.1.1"
[source]
type = "git"
url = "https://git.amadey.xyz/mozart/greeter"
commit = "d79a99468a158e2b37739404073dcfaab8c12308"
sha256 = "sha256-1IV9HrdYoQOFcI3bP280/CYsdmuYvuMFK9hvjdanNto="
[lock]
nixpkgs_rev = "d233902339c02a9c334e7e593de68855ad26c4cb"
flake_utils_rev = "11707dc2f618dd54ca8739b309ec4fc024de578b"
[meta]
description = "minimal cargoxx demo library — greets you"
license = "MIT"

3
runner/.gitignore vendored
View File

@@ -6,3 +6,6 @@ result
# committed; the public key is regenerated per deployment too # committed; the public key is regenerated per deployment too
# (`nix-store --generate-binary-cache-key`). # (`nix-store --generate-binary-cache-key`).
cache/ cache/
# Caddy state: ACME account + issued certs + on-disk config tree.
caddy/

43
runner/Caddyfile Normal file
View File

@@ -0,0 +1,43 @@
# Caddy config for the cargoxx binary cache.
#
# The router does PAT (port forwarding) so the *external* world reaches
# us at the standard 80/443 but the *internal* ports are different.
# `http_port` and `https_port` below must match the internal ports the
# router forwards to. Override via runner/.env:
#
# CADDY_HTTP_PORT=8080
# CADDY_HTTPS_PORT=8443
#
# (Those env vars are picked up by compose.yml to publish the ports
# AND injected into this Caddyfile via the {$VAR:default} substitution
# below — Caddy expands env vars natively.)
{
# Internal ports — must equal whatever the router forwards 80/443 to.
http_port {$CADDY_HTTP_PORT:8080}
https_port {$CADDY_HTTPS_PORT:8443}
# ACME's HTTP-01 challenge probe still arrives at host:80 → router
# → :8080; Caddy answers it on the internal port. Auto cert works
# as long as the PAT maps 80 → CADDY_HTTP_PORT and 443 → CADDY_HTTPS_PORT.
email vorontsov@amadey.xyz
}
cache.cargoxx.amadey.xyz {
root * /srv/cache
file_server
# narinfo / nar are immutable per content hash → cache aggressively.
@cache_immutable path *.narinfo *.nar.xz *.nar
header @cache_immutable Cache-Control "public, immutable, max-age=31536000"
# Substituter probe; short cache so new entries land quickly.
@cache_info path /nix-cache-info
header @cache_info Cache-Control "public, max-age=300"
log {
output file /data/access.log {
roll_size 50MiB
roll_keep 5
}
}
}
}

View File

@@ -61,22 +61,28 @@ Self-hosted Gitea Actions runner that validates package PRs.
The `cache/` directory is gitignored. Both keys live alongside The `cache/` directory is gitignored. Both keys live alongside
`compose.yml`; the named volume binds use `${PWD}/cache/...`. `compose.yml`; the named volume binds use `${PWD}/cache/...`.
5. **(optional) Front the store with nginx** so substituters can read it: 5. **Pick the Caddy ports.** `compose.yml` runs Caddy alongside the
runner to HTTPS-front the cache. Because the router does PAT, the
*internal* ports Caddy listens on must equal whatever 80/443 are
forwarded to. Add to `.env`:
```nginx ```env
# /etc/nginx/sites-available/cargoxx-cache CADDY_HTTP_PORT=8080
server { CADDY_HTTPS_PORT=8443
listen 443 ssl;
server_name cache.cargoxx.<your-domain>;
root /path/to/cargoxx-pkgs/runner/cache/store;
autoindex off;
location / { try_files $uri =404; }
}
``` ```
Consumers later need `substituters = https://cache.cargoxx.<your-domain>` Both compose.yml and the Caddyfile pick those up. The Caddyfile
and `trusted-public-keys = <contents of cache.pub>` in their nix already targets `cache.cargoxx.amadey.xyz` and the e-mail
config (bake this into the cargoxx wrapper once ready). `vorontsov@amadey.xyz`; edit if you're deploying somewhere else.
ACME provisioning works as long as the router forwards 80 →
CADDY_HTTP_PORT and 443 → CADDY_HTTPS_PORT, so Let's Encrypt's
HTTP-01 challenge reaches Caddy.
Consumers' substituter config (`substituters = https://cache.<domain>`,
`trusted-public-keys = <cache.pub>`) is baked into cargoxx's own
wrapper (`cargoxx/flake.nix:cargoxxNixConfig`), so any installed
`cargoxx` binary picks them up — no per-user setup needed.
6. **Start the runner**: 6. **Start the runner**:

View File

@@ -1,9 +1,11 @@
# Runs the act_runner that listens to Gitea and spawns one job # Runs two services on the host:
# container per workflow run. The job image (cargoxx-runner-job:latest) # - act_runner — polls Gitea, spawns one job container per workflow
# is built reproducibly from runner/flake.nix — run `nix run .#load-image` # run via the host docker socket. Job image built reproducibly from
# in this directory to load it into the host's Docker daemon before # runner/flake.nix (`nix run .#load-image`).
# starting the runner. # - caddy — HTTPS-fronts the binary cache (./cache/store) so
version: "3.8" # consumers' substituter config can read it. Custom ports because
# the router does PAT (port-forwarding 80→CADDY_HTTP_PORT,
# 443→CADDY_HTTPS_PORT). Set those in .env.
services: services:
runner: runner:
image: docker.io/gitea/act_runner:nightly image: docker.io/gitea/act_runner:nightly
@@ -20,12 +22,26 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
# Binary cache — `validate-pr.yml`'s push step writes `$out` NAR # Binary cache — `validate-pr.yml`'s push step writes `$out` NAR
# archives here. Named volumes (defined below) make the same # archives here. Named volumes (defined below) make the same
# storage reachable from both this runner container AND every # storage reachable from this runner container AND every job
# job container act_runner spawns. nginx (on the host) serves # container act_runner spawns AND the caddy frontend below.
# ./cache/store over HTTPS for consumers' substituter config.
- cargoxx-cache-store:/srv/cargoxx-cache/store - cargoxx-cache-store:/srv/cargoxx-cache/store
- cargoxx-cache-keys:/srv/cargoxx-cache/keys:ro - cargoxx-cache-keys:/srv/cargoxx-cache/keys:ro
caddy:
image: docker.io/caddy:2
restart: unless-stopped
ports:
- "${CADDY_HTTP_PORT:-8080}:${CADDY_HTTP_PORT:-8080}"
- "${CADDY_HTTPS_PORT:-8443}:${CADDY_HTTPS_PORT:-8443}"
environment:
CADDY_HTTP_PORT: "${CADDY_HTTP_PORT:-8080}"
CADDY_HTTPS_PORT: "${CADDY_HTTPS_PORT:-8443}"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- cargoxx-cache-store:/srv/cache:ro
- caddy-data:/data
- caddy-config:/config
volumes: volumes:
cargoxx-cache-store: cargoxx-cache-store:
# Explicit name disables compose's project-prefix so spawned job # Explicit name disables compose's project-prefix so spawned job
@@ -44,3 +60,19 @@ volumes:
type: none type: none
o: bind o: bind
device: "${PWD}/cache/keys" device: "${PWD}/cache/keys"
caddy-data:
# Caddy's own state: ACME account, issued certificates, OCSP
# staples. Persist so we don't re-issue certs every restart.
name: caddy-data
driver: local
driver_opts:
type: none
o: bind
device: "${PWD}/caddy/data"
caddy-config:
name: caddy-config
driver: local
driver_opts:
type: none
o: bind
device: "${PWD}/caddy/config"