# ~$ selfhostedops — copy me: cp .env.example .env # Generate secrets with: openssl rand -hex 32 # Your base domain. Services live at git.* wiki.* vault.* status.* ntfy.* vpn.* # DNS: one wildcard A (and AAAA) record *.ops.example.com -> your server IP DOMAIN=ops.example.com # Let's Encrypt notifications + expiry mails ACME_EMAIL=you@example.com TZ=Europe/Berlin # --- Outline --- OUTLINE_PG_PASSWORD=CHANGE_ME_openssl_rand_hex_32 OUTLINE_SECRET_KEY=CHANGE_ME_openssl_rand_hex_32 OUTLINE_UTILS_SECRET=CHANGE_ME_openssl_rand_hex_32 # From Forgejo: Site Administration -> Applications -> OAuth2 # Redirect URI: https://wiki./auth/oidc.callback OUTLINE_OIDC_CLIENT_ID= OUTLINE_OIDC_CLIENT_SECRET= # --- Vaultwarden --- # Admin panel token (argon2 hash recommended, plain string works to start) VAULTWARDEN_ADMIN_TOKEN=CHANGE_ME_openssl_rand_hex_32 # Flip to false once your team has signed up: VAULTWARDEN_SIGNUPS_ALLOWED=true # Single sign-on against your own Forgejo (episode 4). # From Forgejo: Site Administration -> Applications -> OAuth2 Application # Redirect URI must be EXACTLY: https://vault./identity/connect/oidc-signin VAULTWARDEN_SSO_CLIENT_ID= VAULTWARDEN_SSO_CLIENT_SECRET= # --- wg-easy (optional, --profile vpn) --- # Generate with: docker run --rm ghcr.io/wg-easy/wg-easy wgpw 'yourpassword' WGEASY_PASSWORD_HASH= # --- CI (episode 2, optional: docker compose --profile ci up -d) --- # One shared secret registers the runner declaratively. Generate it with: # openssl rand -hex 20 # Then derive the UUID Forgejo will know it by: # python3 -c 'import uuid,sys;print(uuid.UUID(bytes=sys.argv[1][:16].encode()))' # And register it on the Forgejo side: # docker compose exec -u git forgejo forgejo forgejo-cli actions register \ # --name box-runner --labels docker --secret # A registration token copied from the web UI does NOT work here. RUNNER_SECRET= RUNNER_UUID= # --- ntfy push notifications (episode 6) --- # No secrets here: ntfy keeps its users in its own database. Create them once: # docker compose exec -e NTFY_PASSWORD= ntfy ntfy user add --role=user kuma # docker compose exec ntfy ntfy access kuma alerts write-only # See monitoring/README.md for the full walkthrough. # --- n8n automation (episode 8) --- # No variables needed here either: the workflows keep their credentials inside # n8n, encrypted with the key in /home/node/.n8n/config. That file is inside the # n8n_data volume and therefore inside the nightly backup from episode 7. # # If you would rather pin the key yourself (recommended once more than one # person can restore this box), uncomment the line below and put the same value # in your password manager. It wins over the file, and the file is then never # written. Changing it later makes every existing credential undecryptable. # openssl rand -base64 24 # N8N_ENCRYPTION_KEY= # # The ntfy user the workflows publish as: # docker compose exec -e NTFY_PASSWORD= ntfy ntfy user add --role=user n8n # docker compose exec ntfy ntfy access n8n alerts write-only # docker compose exec ntfy ntfy access n8n deploys write-only # See automation/README.md for the rest. # --- Episode 9: the ops triage agent --------------------------------------- # The shared secret between n8n and the ops-actions runner. Anything that can # present this header can ask for a container restart, so treat it like a key: # openssl rand -hex 24 # The runner still refuses any action or any target that is not on its own # hard-coded allowlists, so a leaked token cannot widen the blast radius. OPS_ACTIONS_TOKEN=