Snapshot both servers: the VPS catalog moves to server/vps, the home server joins as server/home

The catalog in server/containers had drifted from the VPS. Eleven compose
files and twelve units no longer matched what runs, and two running
services, Gbrown_Agent and BillTracker, were missing. server/vps is now a
copy of the live files, and panama-server reads from it.

server/home holds the home server's services in the same shape. They still
run under Docker, so the podman units there are drafts for a later move, and
nothing installs from that tree. PostHog, Sentry and Plausible are checkouts
of upstream repositories. Only their local files are kept, next to an
UPSTREAM file naming the repository and the exact commit.

Every secret in both trees is a ${VAR} reference named in .env.example, or
CHANGE_ME in files that are not compose files. The live servers still hold
some of those values inline, so a live file can differ from its copy on
those lines alone. Existing .env.example files keep their comments, with new
keys appended at the end.

The ignore rules and the secrets contract now cover both trees, plus the
volume/ and volumes/ directories the home server uses.
This commit is contained in:
Gabriel Brown committed 2026-10-06 10:52:47 -04:00
1 parent a664cf68f5
commit 913a57f8a6
146 files changed
+5258 -354

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Beszel AGENT ONLY — the hub now lives on the VPS.
#
# The hub (web UI + database) was moved to the VPS on 2026-08-11 and is reachable at
# https://beszel.gibbyb.com. This host keeps only the agent, which collects metrics and
# serves them to that hub over the WireGuard link (VPS 192.168.2.2 -> here 192.168.1.2:45876).
#
# KEY below is the VPS hub's public key. If the VPS hub is ever rebuilt its keypair
# changes, and this value must be updated to match:
# ssh-keygen -y -f ~/Server/Beszel/volumes/hub/id_ed25519 (run on the VPS)
#
# Previous config, including the local hub service, is in compose.yml.bak-2026-08-11.
#
# The agent uses network_mode: host — that is the documented setup and is what lets it
# read real host network interfaces rather than a container's veth. Docker forbids setting
# hostname/domainname together with host networking, so those keys are absent.
services:
beszel-agent:
image: henrygd/beszel-agent-nvidia:latest
container_name: beszel-agent
network_mode: host
# Give the agent read access to NVIDIA's management interface so Beszel can
# report GPU utilization, temperature, power draw, and VRAM usage.
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [utility]
environment:
- TZ=America/New_York
- PORT=45876
- KEY=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDBWNqxKGRltqXJZg+wlDOtICeLo19ftQ6P3P8+uJg8y
# /boot is a separate 974M partition (nvme1n1p1), not part of the LUKS
# root the agent finds on its own. It filling up is what broke a 1032
# package dnf transaction on 2026-08-09, so it is worth alerting on.
- EXTRA_FILESYSTEMS=/boot
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/agent:/var/lib/beszel-agent
- /var/run/docker.sock:/var/run/docker.sock:ro
- /boot:/boot:ro
- /etc/localtime:/etc/localtime:ro
tty: true
stdin_open: true
restart: unless-stopped
@@ -0,0 +1,18 @@
[Unit]
Description=Podman Compose: Agents/Beszel
After=network-online.target podman.socket
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=%h/Server/Agents/Beszel
ExecStart=/usr/bin/podman compose up -d
ExecStop=/usr/bin/podman compose down
RemainAfterExit=yes
TimeoutStartSec=900
TimeoutStopSec=90
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
+1
View File
@@ -0,0 +1 @@
GITEA_RUNNER_REGISTRATION_TOKEN=CHANGE_ME
+153
View File
@@ -0,0 +1,153 @@
# Gitea Actions runners — 3 parallel runners, each with its own dind sidecar.
#
# Each runner gets an isolated Docker daemon rather than the host socket, so a
# CI job cannot reach the other ~180 containers on this box. Cost: each dind
# keeps its own image cache under ./volumes/runner-N/dind.
#
# The pre-existing host runner (/home/gib/.local/bin/act_runner, name
# "server-gib") is intentionally left running.
#
# Registration token generated with:
# docker exec -u git gitea gitea actions generate-runner-token
# It is reusable — all three runners register with the same one.
networks:
nginx-bridge:
external: true
x-runner-env: &runner-env
TZ: America/New_York
GITEA_INSTANCE_URL: https://git.gbrown.org
GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN}
GITEA_RUNNER_LABELS: "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04,ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
DOCKER_TLS_VERIFY: "1"
DOCKER_CERT_PATH: /certs/client
CONFIG_FILE: /data/config.yml
x-dind-env: &dind-env
TZ: America/New_York
DOCKER_TLS_CERTDIR: /certs
services:
gitea-runner-1:
image: gitea/act_runner:latest
container_name: gitea-runner-1
hostname: gitea-runner-1
domainname: git.gbrown.org
networks: ['nginx-bridge']
environment:
<<: *runner-env
GITEA_RUNNER_NAME: gitea-runner-1
DOCKER_HOST: tcp://gitea-runner-1-dind:2376
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-1/data:/data
- ./volumes/runner-1/certs:/certs
- /etc/localtime:/etc/localtime:ro
depends_on:
- gitea-runner-1-dind
tty: true
stdin_open: true
restart: unless-stopped
gitea-runner-1-dind:
image: docker:dind
container_name: gitea-runner-1-dind
hostname: gitea-runner-1-dind
domainname: git.gbrown.org
networks: ['nginx-bridge']
privileged: true
environment:
<<: *dind-env
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-1/certs:/certs
- ./volumes/runner-1/dind:/var/lib/docker
- /etc/localtime:/etc/localtime:ro
tty: true
stdin_open: true
restart: unless-stopped
gitea-runner-2:
image: gitea/act_runner:latest
container_name: gitea-runner-2
hostname: gitea-runner-2
domainname: git.gbrown.org
networks: ['nginx-bridge']
environment:
<<: *runner-env
GITEA_RUNNER_NAME: gitea-runner-2
DOCKER_HOST: tcp://gitea-runner-2-dind:2376
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-2/data:/data
- ./volumes/runner-2/certs:/certs
- /etc/localtime:/etc/localtime:ro
depends_on:
- gitea-runner-2-dind
tty: true
stdin_open: true
restart: unless-stopped
gitea-runner-2-dind:
image: docker:dind
container_name: gitea-runner-2-dind
hostname: gitea-runner-2-dind
domainname: git.gbrown.org
networks: ['nginx-bridge']
privileged: true
environment:
<<: *dind-env
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-2/certs:/certs
- ./volumes/runner-2/dind:/var/lib/docker
- /etc/localtime:/etc/localtime:ro
tty: true
stdin_open: true
restart: unless-stopped
gitea-runner-3:
image: gitea/act_runner:latest
container_name: gitea-runner-3
hostname: gitea-runner-3
domainname: git.gbrown.org
networks: ['nginx-bridge']
environment:
<<: *runner-env
GITEA_RUNNER_NAME: gitea-runner-3
DOCKER_HOST: tcp://gitea-runner-3-dind:2376
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-3/data:/data
- ./volumes/runner-3/certs:/certs
- /etc/localtime:/etc/localtime:ro
depends_on:
- gitea-runner-3-dind
tty: true
stdin_open: true
restart: unless-stopped
gitea-runner-3-dind:
image: docker:dind
container_name: gitea-runner-3-dind
hostname: gitea-runner-3-dind
domainname: git.gbrown.org
networks: ['nginx-bridge']
privileged: true
environment:
<<: *dind-env
labels:
com.centurylinklabs.watchtower.enable: "true"
volumes:
- ./volumes/runner-3/certs:/certs
- ./volumes/runner-3/dind:/var/lib/docker
- /etc/localtime:/etc/localtime:ro
tty: true
stdin_open: true
restart: unless-stopped
@@ -0,0 +1,18 @@
[Unit]
Description=Podman Compose: Agents/Gitea
After=network-online.target podman.socket
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=%h/Server/Agents/Gitea
ExecStart=/usr/bin/podman compose up -d
ExecStop=/usr/bin/podman compose down
RemainAfterExit=yes
TimeoutStartSec=900
TimeoutStopSec=90
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
+39
View File
@@ -0,0 +1,39 @@
services:
# portainer:
# image: portainer/portainer-ee:latest
# container_name: portainer
# hostname: portainer
# domainname: port.gbrown.org
# networks:
# - nginx-bridge
# labels:
# com.centurylinklabs.watchtower.enable: "true"
# ports:
# - 9443:9443
# volumes:
# - ./volumes/data:/data
# - /var/run/docker.sock:/var/run/docker.sock
# tty: true
# stdin_open: true
# restart: unless-stopped
portainer-agent:
image: portainer/agent:2.33.2
container_name: portainer-agent
hostname: portainer-agent
networks:
- nginx-bridge
labels:
com.centurylinklabs.watchtower.enable: "true"
ports: ["9001:9001"]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- /:/host
tty: true
stdin_open: true
restart: unless-stopped
networks:
nginx-bridge:
external: true
@@ -0,0 +1,18 @@
[Unit]
Description=Podman Compose: Agents/Portainer
After=network-online.target podman.socket
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=%h/Server/Agents/Portainer
ExecStart=/usr/bin/podman compose up -d
ExecStop=/usr/bin/podman compose down
RemainAfterExit=yes
TimeoutStartSec=900
TimeoutStopSec=90
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target