M11: reproducible deploy pipeline
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.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# CI gate for GoblinPay. Mirror of .github/workflows/ci.yml.
|
||||
#
|
||||
# What runs where:
|
||||
# - fmt + the gp-core clippy/test gate run on ANY runner: gp-core is
|
||||
# self-contained (no out-of-repo deps), and it holds the domain logic
|
||||
# (config, invoices, matching, webhooks, rates, the connector seam).
|
||||
# - The FULL gate (gp-wallet + gp-nostr + gp-server, via ./ci.sh) needs the
|
||||
# sibling checkouts next to the repo: nip44/ and nym/ (the Nostr/Nym path)
|
||||
# and goblin/ (the gp-goblin-sender round-trip gate). Where the workspace is
|
||||
# laid out like the deploy host, it runs too; otherwise it is skipped with a
|
||||
# note. `-p` scoping always keeps the goblin-tree dev crate off the money
|
||||
# path build.
|
||||
name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
jobs:
|
||||
rust:
|
||||
name: fmt / clippy / test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Format check (whole workspace)
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Clippy (gp-core, deny warnings)
|
||||
run: cargo clippy -p gp-core --all-targets -- -D warnings
|
||||
|
||||
- name: Test (gp-core)
|
||||
run: cargo test -p gp-core --locked
|
||||
|
||||
- name: Full gate (when sibling checkouts are present)
|
||||
run: |
|
||||
if [ -d ../nip44 ] && [ -d ../nym/smolmix/core ] && [ -d ../goblin ]; then
|
||||
echo "Workspace siblings present — running the full ./ci.sh gate."
|
||||
./ci.sh
|
||||
else
|
||||
echo "nip44/nym/goblin siblings absent on this runner;"
|
||||
echo "the full gp-server gate runs via ./ci.sh on the deploy host."
|
||||
fi
|
||||
@@ -0,0 +1,58 @@
|
||||
# CI gate for GoblinPay. Mirror of .gitea/workflows/ci.yml.
|
||||
#
|
||||
# What runs where:
|
||||
# - fmt + the gp-core clippy/test gate run on ANY runner: gp-core is
|
||||
# self-contained (no out-of-repo deps), and it holds the domain logic
|
||||
# (config, invoices, matching, webhooks, rates, the connector seam).
|
||||
# - The FULL gate (gp-wallet + gp-nostr + gp-server, via ./ci.sh) needs the
|
||||
# sibling checkouts next to the repo: nip44/ and nym/ (the Nostr/Nym path)
|
||||
# and goblin/ (the gp-goblin-sender round-trip gate). Where the workspace is
|
||||
# laid out like the deploy host, it runs too; otherwise it is skipped with a
|
||||
# note. `-p` scoping always keeps the goblin-tree dev crate off the money
|
||||
# path build.
|
||||
name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
jobs:
|
||||
rust:
|
||||
name: fmt / clippy / test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Format check (whole workspace)
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Clippy (gp-core, deny warnings)
|
||||
run: cargo clippy -p gp-core --all-targets -- -D warnings
|
||||
|
||||
- name: Test (gp-core)
|
||||
run: cargo test -p gp-core --locked
|
||||
|
||||
- name: Full gate (when sibling checkouts are present)
|
||||
run: |
|
||||
if [ -d ../nip44 ] && [ -d ../nym/smolmix/core ] && [ -d ../goblin ]; then
|
||||
echo "Workspace siblings present — running the full ./ci.sh gate."
|
||||
./ci.sh
|
||||
else
|
||||
echo "nip44/nym/goblin siblings absent on this runner;"
|
||||
echo "the full gp-server gate runs via ./ci.sh on the deploy host."
|
||||
fi
|
||||
@@ -0,0 +1,39 @@
|
||||
# GoblinPay environment. Copy to /etc/goblinpay.env (bare metal) or deploy/.env
|
||||
# (docker compose), then edit. NON-SECRET config only: the Grin seed and the
|
||||
# wallet password live as mode-0400 files (systemd LoadCredential / the compose
|
||||
# ./secrets mount), never in this file.
|
||||
|
||||
# --- domain / URLs ---
|
||||
# docker-compose serves GoblinPay on GP_DOMAIN and the bundled relay on
|
||||
# relay.<GP_DOMAIN>; point BOTH DNS records at this host before `compose up`.
|
||||
GP_DOMAIN=pay.example
|
||||
GP_PUBLIC_URL=https://pay.example
|
||||
|
||||
# --- relay (bundled is the default: GoblinPay runs its own relay) ---
|
||||
GP_RELAY_MODE=bundled
|
||||
# The bundled relay's PUBLIC url: it is BOTH dialed by the server AND advertised
|
||||
# to payers in the checkout nprofile, so it must be reachable from the internet.
|
||||
GP_BUNDLED_RELAY_URL=wss://relay.pay.example
|
||||
# For GP_RELAY_MODE=external instead, drop the bundled relay and set:
|
||||
#GP_RELAY_MODE=external
|
||||
#GP_RELAYS=wss://relay.damus.io,wss://nos.lol
|
||||
|
||||
# --- Grin node (read-only: confirmations + balance) ---
|
||||
GP_NODE_URL=https://main.gri.mw
|
||||
|
||||
# --- mixnet ---
|
||||
# on (default) routes THIS server's relay traffic over the Nym mixnet. off is a
|
||||
# supported production posture (server-side clearnet): the payer's Goblin Wallet
|
||||
# still provides sender privacy and the payload stays gift-wrapped end to end.
|
||||
GP_NYM=on
|
||||
|
||||
# --- API / admin tokens (bearer capabilities; use strong random values) ---
|
||||
GP_API_TOKEN=change-me-api-token
|
||||
GP_ADMIN_TOKEN=change-me-admin-token
|
||||
|
||||
# --- webhook to your store (optional; the URL requires the secret) ---
|
||||
#GP_WEBHOOK_URL=https://your-store/hook
|
||||
#GP_WEBHOOK_SECRET=change-me-webhook-secret
|
||||
|
||||
# --- default payment-matching mode: memo | derived | amount ---
|
||||
GP_MATCH_MODE=derived
|
||||
@@ -0,0 +1,23 @@
|
||||
# Caddy reverse proxy for a GoblinPay till, with automatic HTTPS.
|
||||
#
|
||||
# Two names on one host (point both A/AAAA records at this server before
|
||||
# `docker compose up`, so Caddy can obtain certificates):
|
||||
# {$GP_DOMAIN} -> the GoblinPay checkout pages + REST API (gp-server)
|
||||
# relay.{$GP_DOMAIN} -> the bundled nostr-rs-relay (payers connect here; it
|
||||
# is what the checkout nprofile advertises)
|
||||
#
|
||||
# The relay gets its OWN subdomain rather than a path on the main domain so
|
||||
# there is no path rewriting: nostr-rs-relay serves both the WebSocket relay
|
||||
# protocol and the NIP-11 relay-info document at the root.
|
||||
#
|
||||
# GP_DOMAIN is injected from the environment by docker-compose.
|
||||
|
||||
{$GP_DOMAIN} {
|
||||
encode gzip
|
||||
reverse_proxy gp-server:8080
|
||||
}
|
||||
|
||||
relay.{$GP_DOMAIN} {
|
||||
# WebSocket upgrades and the NIP-11 document both go straight through.
|
||||
reverse_proxy relay:7777
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
# Multi-stage build for the GoblinPay server, run as a non-root user.
|
||||
#
|
||||
# IMPORTANT — build context is the WORKSPACE PARENT, not the repo.
|
||||
# The Nostr/Nym money path depends on two crates that live next to this repo,
|
||||
# not inside it (see crates/gp-nostr/Cargo.toml):
|
||||
# nip44 -> ../nip44 (the NIP-44 v3 companion crate)
|
||||
# smolmix-> ../nym/smolmix/core (the in-process Nym mixnet)
|
||||
# So the image must be built from the directory that contains GoblinPay/,
|
||||
# nip44/, and nym/ side by side. docker-compose.yml already sets
|
||||
# `build.context: ../..` for this; to build by hand:
|
||||
#
|
||||
# cd "<workspace parent containing GoblinPay, nip44, nym>"
|
||||
# docker build -f GoblinPay/deploy/Dockerfile -t goblinpay:latest .
|
||||
#
|
||||
# Only `-p gp-server` is built, which EXCLUDES the gp-goblin-sender dev crate
|
||||
# (it needs the goblin wallet tree, absent on servers). gp-wallet's grin_wallet
|
||||
# crates are fetched from git during the build.
|
||||
|
||||
# ---- builder ----
|
||||
FROM rust:1-bookworm AS builder
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends clang cmake pkg-config libssl-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /build
|
||||
|
||||
# The three trees the gp-server dependency graph needs, in the same relative
|
||||
# layout the path deps expect (nip44 and nym are siblings of GoblinPay).
|
||||
COPY GoblinPay ./GoblinPay
|
||||
COPY nip44 ./nip44
|
||||
COPY nym ./nym
|
||||
|
||||
WORKDIR /build/GoblinPay
|
||||
# Build ONLY gp-server (and its deps); never the goblin-tree dev crate.
|
||||
RUN cargo build --release --locked -p gp-server
|
||||
|
||||
# ---- runtime ----
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
# ca-certificates for outbound TLS (node reads, CoinGecko, relays); curl for the
|
||||
# healthcheck.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Non-root user; wallet files, seed-at-rest, and the SQLite db live under /data.
|
||||
RUN useradd --system --uid 10001 --home-dir /data --shell /usr/sbin/nologin goblinpay \
|
||||
&& mkdir -p /data \
|
||||
&& chown -R goblinpay:goblinpay /data
|
||||
|
||||
COPY --from=builder /build/GoblinPay/target/release/gp-server /usr/local/bin/gp-server
|
||||
|
||||
USER goblinpay
|
||||
WORKDIR /data
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Bind on all interfaces inside the container (Caddy is the only thing in front);
|
||||
# keep state under the /data volume. Money/identity secrets are injected at run
|
||||
# time via the *_FILE mounted-secret variants, never baked into the image.
|
||||
ENV GP_BIND=0.0.0.0:8080 \
|
||||
GP_DB_PATH=/data/goblinpay.db \
|
||||
GP_DATA_DIR=/data/gp-data
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD curl -fsS http://127.0.0.1:8080/health || exit 1
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/gp-server"]
|
||||
@@ -0,0 +1,89 @@
|
||||
# A full, self-contained GoblinPay till: the server, its BUNDLED relay, and an
|
||||
# auto-HTTPS reverse proxy.
|
||||
#
|
||||
# cd deploy
|
||||
# cp .env.example .env # then edit it (domain, tokens)
|
||||
# mkdir -p secrets # drop the mounted-secret files in here
|
||||
# docker compose up -d
|
||||
#
|
||||
# gives you:
|
||||
# - gp-server : the GoblinPay payment server (this repo)
|
||||
# - relay : a stock nostr-rs-relay, the bundled relay GP_RELAY_MODE=bundled
|
||||
# points at (so no third-party relay is needed)
|
||||
# - caddy : auto-TLS reverse proxy terminating HTTPS for both
|
||||
#
|
||||
# Set GP_DOMAIN in .env to your own domain BEFORE bringing it up: Caddy obtains
|
||||
# a certificate for it, so DNS must already point at this host.
|
||||
#
|
||||
# NOTE on the build context: gp-server's Nostr/Nym path depends on the sibling
|
||||
# crates nip44/ and nym/ (see deploy/Dockerfile), so the build context is the
|
||||
# workspace parent (`../..`) that holds GoblinPay, nip44, and nym.
|
||||
|
||||
services:
|
||||
gp-server:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: GoblinPay/deploy/Dockerfile
|
||||
image: goblinpay:latest
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
# Bundled relay (default mode). GP_BUNDLED_RELAY_URL is BOTH dialed by the
|
||||
# server and advertised to payers in the nprofile, so it must be the
|
||||
# relay's PUBLIC url (payers connect here); the server reaches it back
|
||||
# through Caddy.
|
||||
GP_RELAY_MODE: bundled
|
||||
GP_BUNDLED_RELAY_URL: ${GP_BUNDLED_RELAY_URL:-wss://relay.${GP_DOMAIN}}
|
||||
GP_PUBLIC_URL: ${GP_PUBLIC_URL:-https://${GP_DOMAIN}}
|
||||
GP_BIND: 0.0.0.0:8080
|
||||
GP_DB_PATH: /data/goblinpay.db
|
||||
GP_DATA_DIR: /data/gp-data
|
||||
# Money/identity secrets come from mounted files (never the image/env):
|
||||
GP_MNEMONIC_FILE: /run/secrets/gp_mnemonic
|
||||
GP_WALLET_PASSWORD_FILE: /run/secrets/gp_wallet_password
|
||||
GP_NCRYPTSEC_FILE: /run/secrets/gp_ncryptsec
|
||||
volumes:
|
||||
- gp-data:/data
|
||||
- ./secrets:/run/secrets:ro
|
||||
expose:
|
||||
- "8080"
|
||||
depends_on:
|
||||
- relay
|
||||
|
||||
relay:
|
||||
image: scsibug/nostr-rs-relay:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./relay/nostr-rs-relay.toml:/usr/src/app/config.toml:ro
|
||||
- relay-data:/usr/src/app/db
|
||||
expose:
|
||||
- "7777"
|
||||
# Bound the relay's footprint so an unauthenticated flood cannot starve the
|
||||
# till or proxy on the same host.
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: "1.0"
|
||||
|
||||
caddy:
|
||||
image: caddy:2
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- gp-server
|
||||
- relay
|
||||
environment:
|
||||
GP_DOMAIN: ${GP_DOMAIN:-pay.example}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy-data:/data
|
||||
- caddy-config:/config
|
||||
|
||||
volumes:
|
||||
gp-data:
|
||||
relay-data:
|
||||
caddy-data:
|
||||
caddy-config:
|
||||
@@ -0,0 +1,80 @@
|
||||
# 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
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-command bare-metal bootstrap for the GoblinPay server:
|
||||
# - builds the release binary (gp-server only; never the goblin-tree dev crate)
|
||||
# - installs it to /usr/local/bin
|
||||
# - creates the managed state dir and the 0700 secrets dir
|
||||
# - installs an env file from deploy/.env.example (if absent)
|
||||
# - installs and enables the hardened systemd unit
|
||||
#
|
||||
# Re-runnable: it never overwrites an existing /etc/goblinpay.env.
|
||||
# Requires: a Rust toolchain (cargo) and root (sudo) for the install steps.
|
||||
#
|
||||
# BUILD PREREQUISITE: gp-server's Nostr/Nym path depends on the sibling crates
|
||||
# nip44/ and nym/ (see crates/gp-nostr/Cargo.toml). They must sit next to this
|
||||
# repo, exactly as on the deploy host. `-p gp-server` deliberately excludes the
|
||||
# gp-goblin-sender dev crate, which needs the (absent) goblin wallet tree.
|
||||
#
|
||||
# After it finishes, edit /etc/goblinpay.env and drop the secret files into
|
||||
# /etc/goblinpay/secrets (mnemonic, wallet_password), then:
|
||||
# sudo systemctl restart gp-server
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
BIN=/usr/local/bin/gp-server
|
||||
ENV_FILE=/etc/goblinpay.env
|
||||
UNIT=/etc/systemd/system/gp-server.service
|
||||
STATE_DIR=/var/lib/goblinpay
|
||||
SECRETS_DIR=/etc/goblinpay/secrets
|
||||
|
||||
say() { printf '\033[1;33m==>\033[0m %s\n' "$1"; }
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
SUDO=sudo
|
||||
else
|
||||
SUDO=""
|
||||
fi
|
||||
|
||||
say "Building release binary (cargo build --release --locked -p gp-server)"
|
||||
( cd "$REPO_DIR" && cargo build --release --locked -p gp-server )
|
||||
|
||||
say "Installing binary to $BIN"
|
||||
$SUDO install -m0755 "$REPO_DIR/target/release/gp-server" "$BIN"
|
||||
|
||||
say "Creating state directory $STATE_DIR (0700)"
|
||||
$SUDO install -d -m0700 "$STATE_DIR"
|
||||
|
||||
say "Creating secrets directory $SECRETS_DIR (0700)"
|
||||
$SUDO install -d -m0700 "$SECRETS_DIR"
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
say "Env file $ENV_FILE already exists — leaving it untouched"
|
||||
else
|
||||
say "Installing env file to $ENV_FILE (EDIT IT: domain, node, tokens)"
|
||||
$SUDO install -m0640 "$REPO_DIR/deploy/.env.example" "$ENV_FILE"
|
||||
fi
|
||||
|
||||
say "Installing systemd unit to $UNIT"
|
||||
$SUDO install -m0644 "$REPO_DIR/deploy/gp-server.service" "$UNIT"
|
||||
|
||||
say "Reloading systemd and enabling the service"
|
||||
$SUDO systemctl daemon-reload
|
||||
$SUDO systemctl enable gp-server
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Done. Next steps:
|
||||
1. Edit $ENV_FILE — set GP_PUBLIC_URL, GP_NODE_URL, GP_BUNDLED_RELAY_URL,
|
||||
GP_API_TOKEN, GP_ADMIN_TOKEN (and GP_WEBHOOK_URL/GP_WEBHOOK_SECRET if used).
|
||||
2. Write the wallet secrets (root-owned, mode 0400):
|
||||
sudo install -m0400 /dev/stdin $SECRETS_DIR/mnemonic <<<'your 24 words'
|
||||
sudo install -m0400 /dev/stdin $SECRETS_DIR/wallet_password <<<'your password'
|
||||
3. Run the bundled relay (deploy/docker-compose.yml) or point
|
||||
GP_BUNDLED_RELAY_URL at a relay you control, and put a TLS reverse proxy
|
||||
in front (see deploy/Caddyfile).
|
||||
4. Start it: $SUDO systemctl start gp-server
|
||||
5. Check it: curl -s http://127.0.0.1:8080/health
|
||||
EOF
|
||||
Reference in New Issue
Block a user