From 457c143954864870d2cd0998107e88f383cb526a Mon Sep 17 00:00:00 2001 From: svatantrya Date: Wed, 14 Oct 2026 18:29:39 -0400 Subject: [PATCH] chore: unify DB env vars and harden local Postgres startup - Use BAL_SERVER_DB_* / BAL_SERVER_PG_DSN in bal-pusher, Dockerfiles, scripts and docs instead of the BAL_PUSHER_DB_* duplicates - Default BAL_SERVER_URL to http://127.0.0.1:9133 - Extract PostgreSQL container startup into a shared pg-server.sh sourced by bal-server.sh and bal-pusher.sh - Read the Postgres password from BAL_PG_PASSWORD instead of hardcoding it, and stop printing the password-bearing DSN - Redact a real-looking Gitea token from .env.example (revoke it if it was live) --- .env.example | 11 +++++++--- Dockerfile | 1 - Dockerfile.release | 1 - README.md | 2 +- bal-pusher.sh | 20 ++++++++++++++--- bal-server.sh | 26 +--------------------- contrib/download_and_install_bal.sh | 2 +- docs/04_modules_detail.md | 2 +- docs/06_database_schema.md | 2 +- docs/07_deployment_and_ops.md | 4 ++-- pg-server.sh | 34 +++++++++++++++++++++++++++++ src/bin/bal-pusher.rs | 14 ++++++------ 12 files changed, 73 insertions(+), 46 deletions(-) mode change 100644 => 100755 bal-pusher.sh create mode 100755 pg-server.sh diff --git a/.env.example b/.env.example index ffe2e0b..4feec72 100644 --- a/.env.example +++ b/.env.example @@ -3,8 +3,7 @@ # DO NOT commit the real token to git! # This file is in .gitignore and should not be committed to git GITEA_API_TOKEN=your_gitea_api_token_here -# Example: GITEA_API_TOKEN=***REMOVED*** -# (replace with your actual token after revoking the old one) +# If a token was ever committed, revoke it and set a new one via the environment. # === bal-server === # !!! WARNING: Never bind to 0.0.0.0 in production. Use 127.0.0.1 and place @@ -33,8 +32,14 @@ BAL_SERVER_ACTIX_DEFAULT_BURST=100 BAL_SERVER_ACTIX_WORKERS=4 BAL_SERVER_ACTIX_MAX_CONNECTIONS=100 +# === PostgreSQL (optional; used by pg-server.sh) === +# pg-server.sh requires BAL_PG_PASSWORD to be set; never commit a real password. +BAL_PG_PASSWORD=change_me +BAL_PG_USER=bal +BAL_PG_DB=baldb + # === bal-pusher === -BAL_PUSHER_DB_FILE=/var/bal/bal.db +BAL_SERVER_DB_FILE=/var/bal/bal.db BAL_PUSHER_BITCOIN_DIR=/home/bal/.bitcoin BAL_PUSHER_SEND_STATS=false BAL_SERVER_URL=http://127.0.0.1:9137 diff --git a/Dockerfile b/Dockerfile index b312094..9ace14e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,7 +82,6 @@ ENV RUST_LOG=info \ BAL_SERVER_BIND_ADDRESS=127.0.0.1 \ BAL_SERVER_BIND_PORT=9137 \ BAL_SERVER_DB_FILE=/var/bal/bal.db \ - BAL_PUSHER_DB_FILE=/var/bal/bal.db \ BAL_SERVER_URL=http://127.0.0.1:9137 \ BAL_SERVER_PUB_KEY_PATH=/var/bal/public_key.pem \ SSL_KEY_PATH=/var/bal/private_key.pem diff --git a/Dockerfile.release b/Dockerfile.release index e3b56f0..6edb40a 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -90,7 +90,6 @@ ENV RUST_LOG=info \ BAL_SERVER_BIND_ADDRESS=127.0.0.1 \ BAL_SERVER_BIND_PORT=9137 \ BAL_SERVER_DB_FILE=/var/bal/bal.db \ - BAL_PUSHER_DB_FILE=/var/bal/bal.db \ BAL_SERVER_URL=http://127.0.0.1:9137 \ BAL_SERVER_PUB_KEY_PATH=/var/bal/public_key.pem \ SSL_KEY_PATH=/var/bal/private_key.pem diff --git a/README.md b/README.md index eb42de3..6850749 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ If no network is specified, defaults to `bitcoin`. | Variable | Description | Default | | --- | --- | --- | -| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` | +| `BAL_SERVER_DB_FILE` | Path to the SQLite3 database file. | `bal.db` | | `BAL_PUSHER_SEND_STATS` | Send stats to welist server. | `false` | | `BAL_SERVER_URL` | URL of bal-server (for stats reporting). | - | | `SSL_KEY_PATH` | Ed25519 private key for signing stats reports. | `private_key.pem` | diff --git a/bal-pusher.sh b/bal-pusher.sh old mode 100644 new mode 100755 index 901f5cc..96d2c9b --- a/bal-pusher.sh +++ b/bal-pusher.sh @@ -1,15 +1,29 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +. "$SCRIPT_DIR/lib.sh" + +WORKING_DIR=$(pwd) + export RUST_LOG=trace -export BAL_PUSHER_DB_FILE="$(pwd)/bal.db" +export BAL_SERVER_DB_FILE="$WORKING_DIR/bal.db" +export BAL_SERVER_DB_BACKEND="postgresql" #export BAL_PUSHER_BITCOIN_COOKIE_FILE=/~/.bitcoin/.cookie #export BAL_PUSHER_REGTEST_COOKIE_FILE=/~/.bitcoin/regtest/.cookie #export BAL_PUSHER_TESTNET_COOKIE_FILE=/~/.bitcoin/testnet3/.cookie #export BAL_PUSHER_SIGNET_COOKIE_FILE=/~/.bitcoin/signet/.cookie export BAL_PUSHER_REGTEST_ZMQ_HASHBLOCK=tcp://127.0.0.1:21332 -export BAL_PUSHER_SEND_STATS=true +export BAL_PUSHER_SEND_STATS=true export WELIST_SERVER_URL=http://localhost:8086 export WELIST_SKIP_URL_VALIDATION=true export BAL_SERVER_URL="http://127.0.0.1:9133" -export SSL_KEY_PATH="$(pwd)/private_key.pem" +export SSL_KEY_PATH="$WORKING_DIR/private_key.pem" + +if [ "$BAL_SERVER_DB_BACKEND" = "postgresql" ]; then + . "$SCRIPT_DIR/pg-server.sh" +fi + cargo run --bin=bal-pusher regtest --features=pusher diff --git a/bal-server.sh b/bal-server.sh index 006832d..a902ca6 100755 --- a/bal-server.sh +++ b/bal-server.sh @@ -31,31 +31,7 @@ export BAL_SERVER_REGTEST_FIXED_FEE=1000 export BAL_SERVER_DB_BACKEND="postgresql" if [ "$BAL_SERVER_DB_BACKEND" = "postgresql" ]; then - PG_CONTAINER="bal-pg" - PG_DSN="${BAL_SERVER_PG_DSN:-postgres://bal:***REMOVED***@localhost:5432/baldb}" - - docker rm -f "$PG_CONTAINER" 2>/dev/null || true - echo_i "Starting PostgreSQL container..." - docker run -d --name "$PG_CONTAINER" \ - -e POSTGRES_USER=bal \ - -e POSTGRES_PASSWORD=***REMOVED*** \ - -e POSTGRES_DB=baldb \ - -p 5432:5432 postgres:16-alpine - - echo_i "Waiting for PostgreSQL..." - until docker exec "$PG_CONTAINER" pg_isready -U bal >/dev/null 2>&1; do - sleep 1 - done - echo_i "PostgreSQL ready at $PG_DSN" - export BAL_SERVER_PG_DSN="$PG_DSN" - - - cleanup() { - echo_i "Stopping PostgreSQL container..." - docker stop "$PG_CONTAINER" >/dev/null 2>&1 - docker rm "$PG_CONTAINER" >/dev/null 2>&1 - } - trap cleanup EXIT + . "$SCRIPT_DIR/pg-server.sh" fi cargo run --bin=bal-server diff --git a/contrib/download_and_install_bal.sh b/contrib/download_and_install_bal.sh index 66a6067..a56f5b3 100644 --- a/contrib/download_and_install_bal.sh +++ b/contrib/download_and_install_bal.sh @@ -47,7 +47,7 @@ BAL_SERVER_INFO="$info" EOF ) bal_pusher_conf=$(cat << EOF -BAL_PUSHER_DB_FILE=/home/bal/bal.db +BAL_SERVER_DB_FILE=/home/bal/bal.db BAL_PUSHER_BITCOIN_COOKIE_FILE=/home/bitcoin/.bitcoin/.cookie EOF diff --git a/docs/04_modules_detail.md b/docs/04_modules_detail.md index d2c96f9..849e245 100644 --- a/docs/04_modules_detail.md +++ b/docs/04_modules_detail.md @@ -201,7 +201,7 @@ This is the async daemon that monitors the blockchain and pushes pending transac ### Configuration All configuration is via environment variables (no config files): -- `BAL_PUSHER_DB_FILE`: Path to SQLite database. +- `BAL_SERVER_DB_FILE`: Path to SQLite database. - `BAL_PUSHER_BITCOIN_DIR`: Bitcoin data directory (for cookie file path). - `BAL_PUSHER_SEND_STATS`: Enable/disable remote stats reporting. - `BAL_SERVER_URL`: URL of the bal-server for internal communication. diff --git a/docs/06_database_schema.md b/docs/06_database_schema.md index cf57e27..52ae0c2 100644 --- a/docs/06_database_schema.md +++ b/docs/06_database_schema.md @@ -8,7 +8,7 @@ ## Database Technology - **Engine:** `sqlite` (Rust `sqlite` crate, version 0.34.0) -- **File:** `bal.db` (default, configurable via `BAL_SERVER_DB_FILE` / `BAL_PUSHER_DB_FILE`) +- **File:** `bal.db` (default, configurable via `BAL_SERVER_DB_FILE`) - **Connection Management:** Shared `Arc>` in `bal-server`, single connection in `bal-pusher`. - **WAL Mode:** Enabled via `PRAGMA journal_mode=WAL` with retry logic (up to 5 attempts) for concurrent access safety. - **Busy Timeout:** Set to 5000ms via `PRAGMA busy_timeout=5000`. diff --git a/docs/07_deployment_and_ops.md b/docs/07_deployment_and_ops.md index d3c208d..6c410a3 100644 --- a/docs/07_deployment_and_ops.md +++ b/docs/07_deployment_and_ops.md @@ -56,10 +56,10 @@ Example: `BAL_SERVER_REGTEST_ADDRESS=tpub...`, `BAL_SERVER_BITCOIN_FIXED_FEE=500 | Variable | Default | Description | |----------|---------|-------------| -| `BAL_PUSHER_DB_FILE` | `"bal.db"` | Path to the SQLite database file | +| `BAL_SERVER_DB_FILE` | `"bal.db"` | Path to the SQLite database file | | `BAL_PUSHER_BITCOIN_DIR` | `""` | Bitcoin data directory (for cookie file path resolution) | | `BAL_PUSHER_SEND_STATS` | `false` | Enable/disable remote stats reporting | -| `BAL_SERVER_URL` | `"http://localhost/"` | URL of the bal-server for internal communication | +| `BAL_SERVER_URL` | `"http://127.0.0.1:9133"` | URL of the bal-server for internal communication | | `SSL_KEY_PATH` | `"privkey.pem"` | Path to Ed25519 private key for signing stats | | `BAL_PUSHER_PREFER_IPV6` | `false` | Pin HTTP connection to first IPv6 address (for broken IPv4 routes) | | `WELIST_SERVER_URL` | `"https://welist.bitcoin-after.life"` | URL to POST signed stats to (validated against SSRF) | diff --git a/pg-server.sh b/pg-server.sh new file mode 100755 index 0000000..3d8ff0f --- /dev/null +++ b/pg-server.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +. "$SCRIPT_DIR/lib.sh" + +PG_CONTAINER="bal-pg" +PG_USER="${BAL_PG_USER:-bal}" +PG_DB="${BAL_PG_DB:-baldb}" +# The password MUST come from the environment; never hardcode it. +PG_PASSWORD="${BAL_PG_PASSWORD:?BAL_PG_PASSWORD must be set (see .env.example)}" +PG_DSN="${BAL_SERVER_PG_DSN:-postgres://${PG_USER}:${PG_PASSWORD}@localhost:5432/${PG_DB}}" + +if docker ps --format '{{.Names}}' | grep -q "^${PG_CONTAINER}$"; then + echo_i "PostgreSQL container '$PG_CONTAINER' is already running" +elif docker ps -a --format '{{.Names}}' | grep -q "^${PG_CONTAINER}$"; then + echo_i "Starting existing PostgreSQL container '$PG_CONTAINER'..." + docker start "$PG_CONTAINER" >/dev/null 2>&1 +else + echo_i "Creating PostgreSQL container '$PG_CONTAINER'..." + docker run -d --name "$PG_CONTAINER" \ + -e POSTGRES_USER="$PG_USER" \ + -e POSTGRES_PASSWORD="$PG_PASSWORD" \ + -e POSTGRES_DB="$PG_DB" \ + -p 5432:5432 postgres:16-alpine +fi + +echo_i "Waiting for PostgreSQL..." +until docker exec "$PG_CONTAINER" pg_isready -U "$PG_USER" >/dev/null 2>&1; do + sleep 1 +done +# Do not echo the DSN: it embeds the password. +echo_s "PostgreSQL ready (user=$PG_USER, db=$PG_DB, host=localhost:5432)" +export BAL_SERVER_PG_DSN="$PG_DSN" diff --git a/src/bin/bal-pusher.rs b/src/bin/bal-pusher.rs index c8285c8..55c63eb 100644 --- a/src/bin/bal-pusher.rs +++ b/src/bin/bal-pusher.rs @@ -46,9 +46,9 @@ struct MyConfig { impl Default for MyConfig { fn default() -> Self { MyConfig { - db_backend: env::var("BAL_PUSHER_DB_BACKEND").unwrap_or("sqlite".to_string()), - db_file: env::var("BAL_PUSHER_DB_FILE").unwrap_or("bal.db".to_string()), - pg_dsn: env::var("BAL_PUSHER_PG_DSN").unwrap_or_default(), + db_backend: env::var("BAL_SERVER_DB_BACKEND").unwrap_or("sqlite".to_string()), + db_file: env::var("BAL_SERVER_DB_FILE").unwrap_or("bal.db".to_string()), + pg_dsn: env::var("BAL_SERVER_PG_DSN").unwrap_or_default(), bitcoin_dir: env::var("BAL_PUSHER_BITCOIN_DIR").unwrap_or("".to_string()), regtest: get_network_params_default(Network::Regtest), testnet: get_network_params_default(Network::Testnet), @@ -59,7 +59,7 @@ impl Default for MyConfig { .unwrap_or("false".to_string()) .parse::() .unwrap_or(false), - url: env::var("BAL_SERVER_URL").unwrap_or("http://localhost/".to_string()), + url: env::var("BAL_SERVER_URL").unwrap_or("http://127.0.0.1:9133".to_string()), ssl_key_path: env::var("SSL_KEY_PATH").unwrap_or("privkey.pem".to_string()), } } @@ -423,13 +423,13 @@ fn sign_message(private_key_path: &str, message: &str) -> String { } fn parse_env(cfg: &mut MyConfig) { - if let Ok(value) = env::var("BAL_PUSHER_DB_BACKEND") { + if let Ok(value) = env::var("BAL_SERVER_DB_BACKEND") { cfg.db_backend = value; } - if let Ok(value) = env::var("BAL_PUSHER_DB_FILE") { + if let Ok(value) = env::var("BAL_SERVER_DB_FILE") { cfg.db_file = value; } - if let Ok(value) = env::var("BAL_PUSHER_PG_DSN") { + if let Ok(value) = env::var("BAL_SERVER_PG_DSN") { cfg.pg_dsn = value; } cfg.regtest = parse_env_netconfig(cfg, "regtest");