{ config, pkgs, lib, ...}: { virtualisation.oci-containers = { backend = "podman"; containers = { mempool-db = { image = "mariadb:11"; autoStart = true; environment = { MARIADB_DATABASE = "mempool"; MARIADB_USER = "mempool"; MARIADB_PASSWORD = "mempool"; MARIADB_ROOT_PASSWORD = "root"; }; volumes = [ "/srv/mempool/mysql:/var/lib/mysql" ]; }; mempool-backend = { image = "mempool/backend:latest"; autoStart = true; dependsOn = [ "mempool-db" ]; ports = [ "127.0.0.1:8999:8999" ]; extraOptions = [ "--add-host=host.containers.internal:host-gateway" ]; environment = { MEMPOOL_NETWORK = "mainnet"; MEMPOOL_BACKEND = "electrum"; MEMPOOL_HTTP_PORT = "8999"; ELECTRUM_HOST = "host.containers.internal"; ELECTRUM_PORT = "50001"; ELECTRUM_TLS_ENABLED = "false"; CORE_RPC_HOST = "host.containers.internal"; CORE_RPC_PORT = "8332"; CORE_RPC_COOKIE = "true"; CORE_RPC_COOKIE_PATH = "/bitcoin/.cookie"; DATABASE_ENABLED = "true"; DATABASE_HOST = "mempool-db"; DATABASE_PORT = "3306"; DATABASE_DATABASE = "mempool"; DATABASE_USERNAME = "mempool"; DATABASE_PASSWORD = "mempool"; STATISTICS_ENABLED = "true"; }; volumes = [ "/run/mempool/bitcoind.cookie:/bitcoin/.cookie:ro" ]; }; mempool-frontend = { image = "mempool/frontend:latest"; autoStart = true; ports = [ "127.0.0.1:8998:8080" ]; environment = { NGINX_HOSTNAME = "mempool.tobiasostner.de"; NGINX_PORT = "443"; NGINX_PROTOCOL = "https"; }; }; }; }; systemd.tmpfiles.rules = lib.mkAfter [ "d /run/mempool 0755 root root - -" ]; # Copy cookie once systemd.services.mempool-cookie = { description = "Expose bitcoind cookie for mempool-backend"; after = [ "bitcoind-mainnet.service" ]; wants = [ "bitcoind-mainnet.service" ]; serviceConfig = { Type = "oneshot"; ExecStart = pkgs.writeShellScript "mempool-cookie" '' set -euo pipefail for i in $(seq 1 60); do if [ -f /var/lib/bitcoind/.cookie ]; then install -m 0644 -o root -g root /var/lib/bitcoind/.cookie /run/mempool/bitcoind.cookie exit 0 fi sleep 1 done echo "Cookie not found after 60s" >&2 exit 1 ''; }; }; # Re-run the cookie copy whenever bitcoind rotates the cookie systemd.paths.mempool-cookie = { description = "Watch bitcoind cookie and refresh mempool copy"; wantedBy = [ "multi-user.target" ]; pathConfig = { PathChanged = "/var/lib/bitcoind/.cookie"; }; }; # When the path triggers, it starts the service systemd.services.mempool-cookie.wantedBy = lib.mkForce [ ]; systemd.paths.mempool-cookie.unitConfig = { Unit = "mempool-cookie.service"; }; systemd.services.podman-mempool-backend = { after = [ "mempool-cookie.service" ]; wants = [ "mempool-cookie.service" ]; }; services.nginx = { appendHttpConfig = '' limit_req_zone $binary_remote_addr zone=mempool_api:10m rate=60r/m; limit_conn_zone $binary_remote_addr zone=mempool_ws:10m; ''; virtualHosts."mempool.tobiasostner.de" = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://127.0.0.1:8998"; extraConfig = '' proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; ''; }; locations."/api/" = { proxyPass = "http://127.0.0.1:8999"; extraConfig = '' limit_req zone=mempool_api burst=30 nodelay; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 2s; proxy_read_timeout 60s; proxy_send_timeout 60s; proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 10s; ''; }; locations."/api/v1/ws" = { proxyPass = "http://127.0.0.1:8999/api/v1/ws"; proxyWebsockets = true; extraConfig = '' limit_conn mempool_ws 3; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 2s; proxy_read_timeout 60s; proxy_send_timeout 60s; proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 10s; ''; }; }; }; networking.firewall.interfaces."podman0".allowedTCPPorts = [ 8332 50001 ]; }