Deploying the developer edition on Earth
Companion to spec.md §17.5. Status: installed and running since 2026-09-27 as the systemd service oxygenhub under the oxygenhub system user, data in /home/oxygenhub/data, HTTP on 7300 and HTTPS on 7343 with a self-signed certificate. oxygen, oxygen-vscode and oxygenhub are hosted under andymccall/ and each checkout has an earth remote.
The host
| Name | earth (earth.andymccall.xyz, IPv6 ULA; 192.168.1.6 on the LAN) |
| OS | Ubuntu 26.04.1 LTS, x86_64, 4 cores, 31 GiB RAM |
| Disk | / 251 GB (95 GB free), /home 1 TB (944 GB free) |
| Already running | sshd :22, a Python service :6400, wren-nest :7842, retroplay-manager in Docker (:8080, :6670) with Postgres and a tetriblox server, two GitHub Actions runners (doomsdayonecom), Docker, containerd |
| Not installed | Rust toolchain, sqlite3 CLI, nginx or caddy, certbot |
| Access | ssh -i ~/.ssh/earth_claude claude@earth; claude has passwordless sudo |
Ports 7300 (HTTP) and 7343 (HTTPS) are free and are the hub's.
Steps
- Toolchain (as
claude):curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal, thensudo apt-get install -y build-essential pkg-config git. - Source: from the development machine,
rsync -a --delete --exclude target --exclude node_modules ~/development/oxygen ~/development/oxygenhub claude@earth:~/src/. Oxygen is never pushed to Git; rsync is the bootstrap, and after the hub runs,oxy pushto the hub itself is the ongoing path. - Build:
cd ~/src/oxygenhub && cargo build --release. - System user and data:
sudo useradd --system --home /home/oxygenhub --create-home oxygenhub,sudo install -o oxygenhub -g oxygenhub -m 0755 target/release/oxygenhub /usr/local/bin/,sudo -u oxygenhub oxygenhub init --data /home/oxygenhub/data --admin andymccall(prints the first admin's one-time password). - Service:
/etc/systemd/system/oxygenhub.servicerunningoxygenhub serve --data /home/oxygenhub/dataasoxygenhub,Restart=on-failure,ProtectSystem=strict,ReadWritePaths=/home/oxygenhub/data,NoNewPrivileges=yes;sudo systemctl enable --now oxygenhub. - TLS: the developer edition generates a self-signed certificate at
init. Download the certificate fromhttps://earth.andymccall.xyz:7343/.well-known/oxyhub-ca.pem(or over plain HTTP on port 7300) and point clients at it withoxy config remote.<name>.ca <file>orOXY_CA. - First repositories: on the development machine,
oxy remote add earth https://oxygenhub.io/andymccall/oxygenin each ofoxygen,oxygen-vscode,oxygenhub, thenoxy push earth. - Updates: rsync, build,
sudo install,sudo systemctl restart oxygenhub.make deployin the hub wraps steps 2, 3 and 8. - Public address (2026-09-30): a Cloudflare tunnel on Earth serves the hub as
https://oxygenhub.io, with a publicly trusted certificate, andbase_urlinhub.tomlis that address, so every link the hub writes uses it. Checkouts push there with no CA set, and subrepo URLs name it too. - Localhost only (2026-09-30): the tunnel connects to
127.0.0.1:7300, so the hub binds127.0.0.1:7300and127.0.0.1:7343and nothing on the LAN reaches it directly;behind_proxy = true(the hub does not yet use client addresses). The Flow runner on Earth pollshttp://127.0.0.1:7300. Backups:hub.toml.before-localhost,~/flow/flow.toml.before-localhost.
Where things are on Earth
| Binaries | /usr/local/bin/oxygenhub, /usr/local/bin/oxy |
| Sources | /home/claude/src/oxygen, /home/claude/src/oxygenhub (rsync targets; the hub itself is the canonical remote) |
| Data | /home/oxygenhub/data (hub.toml, hub.db, keys/, repos/andymccall/*) |
| Push token | /home/oxygenhub/push-token (also in hub.toml); each local checkout has it as remote.earth.token |
| Certificate | /home/oxygenhub/data/keys/tls.crt, served at /.well-known/oxyhub-ca.pem; local copy ~/.config/oxy/earth-ca.pem set as remote.earth.ca |
| Service | sudo systemctl status oxygenhub, sudo journalctl -u oxygenhub |