3fdf4a230c
Multi-stage non-root Dockerfile (builds -p gp-server against the nip44/nym siblings; excludes the goblin-tree dev crate), a full docker-compose (server + bundled nostr-rs-relay + auto-HTTPS Caddy), a hardened systemd unit (DynamicUser, ProtectSystem=strict, NoNewPrivileges, seed via LoadCredential), an install.sh bare-metal bootstrap, .env.example, and an fmt+clippy+test CI workflow for Gitea and GitHub.
81 lines
3.1 KiB
Desktop File
81 lines
3.1 KiB
Desktop File
# Hardened systemd unit for the GoblinPay server on bare metal.
|
|
#
|
|
# Install (or just run deploy/install.sh):
|
|
# sudo install -m0755 target/release/gp-server /usr/local/bin/
|
|
# sudo install -m0640 deploy/.env.example /etc/goblinpay.env # then EDIT it
|
|
# sudo install -m0644 deploy/gp-server.service /etc/systemd/system/
|
|
# sudo mkdir -p /etc/goblinpay/secrets # 0400 secret files
|
|
# sudo systemctl daemon-reload && sudo systemctl enable --now gp-server
|
|
#
|
|
# Unlike goblin-nip05d, this service holds MONEY secrets (the Grin seed and the
|
|
# wallet password) and a wallet data directory. The seed and password are passed
|
|
# as systemd credentials (read by PID1 as root, exposed read-only to the dynamic
|
|
# service user) rather than left world-readable, and the config supports the
|
|
# `*_FILE` mounted-secret variants for exactly this.
|
|
|
|
[Unit]
|
|
Description=GoblinPay — self-hostable, receive-only Grin payment server
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=exec
|
|
# Throwaway unprivileged user allocated at runtime. For a stable data owner,
|
|
# comment this out and set `User=goblinpay` (create the user first).
|
|
DynamicUser=yes
|
|
|
|
# Non-secret config (domain, node, tokens, webhook, relay URL). Read by systemd
|
|
# as root, so a 0640 root:root file is fine even under DynamicUser.
|
|
EnvironmentFile=/etc/goblinpay.env
|
|
|
|
# Money/identity secrets as credentials: the source files stay root-owned 0400;
|
|
# systemd exposes copies under $CREDENTIALS_DIRECTORY (%d), readable by the
|
|
# dynamic service user. Point the wallet at them via the *_FILE variants.
|
|
LoadCredential=gp_mnemonic:/etc/goblinpay/secrets/mnemonic
|
|
LoadCredential=gp_wallet_password:/etc/goblinpay/secrets/wallet_password
|
|
Environment=GP_MNEMONIC_FILE=%d/gp_mnemonic
|
|
Environment=GP_WALLET_PASSWORD_FILE=%d/gp_wallet_password
|
|
# Optional: a NIP-49 encrypted Nostr identity (else a random one is generated
|
|
# and persisted under the data dir on first start). Uncomment with its file:
|
|
#LoadCredential=gp_ncryptsec:/etc/goblinpay/secrets/ncryptsec
|
|
#Environment=GP_NCRYPTSEC_FILE=%d/gp_ncryptsec
|
|
|
|
# Managed state at /var/lib/goblinpay: the SQLite db, the wallet files, and the
|
|
# encrypted seed at rest. 0700 — only the service user may read it.
|
|
StateDirectory=goblinpay
|
|
StateDirectoryMode=0700
|
|
Environment=GP_DB_PATH=/var/lib/goblinpay/goblinpay.db
|
|
Environment=GP_DATA_DIR=/var/lib/goblinpay/gp-data
|
|
|
|
ExecStart=/usr/local/bin/gp-server
|
|
Restart=on-failure
|
|
RestartSec=2
|
|
|
|
# --- hardening ---
|
|
NoNewPrivileges=yes
|
|
ProtectSystem=strict
|
|
ProtectHome=yes
|
|
PrivateTmp=yes
|
|
PrivateDevices=yes
|
|
ProtectKernelTunables=yes
|
|
ProtectKernelModules=yes
|
|
ProtectControlGroups=yes
|
|
ProtectClock=yes
|
|
ProtectHostname=yes
|
|
RestrictNamespaces=yes
|
|
RestrictRealtime=yes
|
|
RestrictSUIDSGID=yes
|
|
LockPersonality=yes
|
|
# If the Nym mixnet stack ever fails to start with a W^X error, comment this out.
|
|
MemoryDenyWriteExecute=yes
|
|
SystemCallArchitectures=native
|
|
SystemCallFilter=@system-service
|
|
SystemCallFilter=~@privileged @resources
|
|
# Only the state directory is writable.
|
|
ReadWritePaths=/var/lib/goblinpay
|
|
# No raw sockets; only IP + unix.
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|