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

+1
View File
@@ -0,0 +1 @@
AGENT_INGEST_SECRET=CHANGE_ME
+43
View File
@@ -0,0 +1,43 @@
# Hetzner VPS (junior.gib, rootless podman): ~/Server/Gbrown_Agent/compose.yml.
# Follows ~/Server/AGENTS.md. AGENT_INGEST_SECRET lives in ./.env (never
# committed). Started by podman-gbrown-agent.service, never by hand.
#
# SELinux:
# - The podman socket is mounted with no relabel flag, ever (AGENTS.md §6).
# - Reading it needs `label:disable`, the same exception portainer and uptime
# have as container-management tooling.
# - Because labeling is off, the NPM logs mount also takes no :z or :Z.
# NPM mounts its data dir with :Z (a private MCS pair), so relabeling it here
# would lock NPM out of its own data.
networks:
nginx-bridge:
external: true
services:
gbrown-agent:
image: git.gbrown.org/gib/gbrown-agent:latest
container_name: gbrown-agent
hostname: gbrown-agent
networks: ['nginx-bridge']
environment:
- TZ=America/New_York
- HOST_ID=vps
- INGEST_URL=https://convex.gbrown.org/ingest
- AGENT_INGEST_SECRET=${AGENT_INGEST_SECRET}
# Reach Convex over WireGuard, not Cloudflare: pin the hostname to the
# Home Server's proxy (192.168.1.2, routed via the `Home` interface). The
# URL stays https with the real hostname, so SNI and the certificate check
# are unchanged.
extra_hosts:
- 'convex.gbrown.org:192.168.1.2'
# The image runs as uid 1000 (bun). keep-id maps it to gib, who owns the
# podman socket and the NPM logs (AGENTS.md §3.2). Never `user: 1000:1000`.
userns_mode: 'keep-id:uid=1000,gid=1000'
volumes:
- /run/user/1000/podman/podman.sock:/var/run/docker.sock # no :Z, ever
- /home/gib/Server/Nginx_Proxy_Manager/volumes/data/logs:/npm-logs:ro
security_opt: ['label:disable', 'no-new-privileges:true']
read_only: true
cap_drop: [ALL]
restart: unless-stopped
stop_grace_period: 10s
@@ -0,0 +1,27 @@
# Rootless user unit for the telemetry agent on junior.gib, from
# ~/Server/podman-example.service. Install (as gib, never sudo):
# cp podman-gbrown-agent.service ~/.config/systemd/user/
# systemctl --user daemon-reload
# systemctl --user enable --now podman-gbrown-agent.service
# Then add gbrown-agent to the lists in ~/Server/verify-rootless.sh, and to
# update-containers.sh if it should follow nightly image updates.
[Unit]
Description=Podman Compose: gbrown telemetry agent
After=network-online.target podman.socket
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=3
[Service]
Type=oneshot
WorkingDirectory=%h/Server/Gbrown_Agent
ExecStart=/usr/bin/podman compose up -d
ExecStop=/usr/bin/podman compose down
RemainAfterExit=yes
TimeoutStartSec=300
TimeoutStopSec=60
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target