nix-bitcoin/docs/lamassu-future-nginx.md
padreug a7d96d2d2e lamassu: simplify to production mode only, document future nginx support
Current state:
- Admin UI runs on port 443 (hardcoded in upstream)
- devMode and nginx options commented out (would conflict with port 443)
- adminPort option removed (not configurable in upstream)

Future implementation documented in docs/lamassu-future-nginx.md:
- Add --ui-port flag to upstream lamassu-server
- Re-enable devMode, adminPort, and nginx options
- Allow nginx as reverse proxy on 443 with admin UI on internal port

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 16:04:37 +01:00

5.2 KiB

Lamassu Server: Future Nginx Implementation

This document describes how to implement nginx reverse proxy support for the lamassu-server module in the future.

Current Limitation

The lamassu-admin-server has hardcoded ports in upstream:

  • Production mode (default): port 443
  • Dev mode (--dev flag): port 8070

This means nginx cannot be used as a reverse proxy on port 443 because the admin UI would already be bound to it.

Required Upstream Changes

1. Add --ui-port flag to admin-server.js

Modify packages/server/lib/new-admin/admin-server.js:

// Change from:
const devMode = require('minimist')(process.argv.slice(2)).dev

// To:
const argv = require('minimist')(process.argv.slice(2))
const devMode = argv.dev
const UI_PORT = argv['ui-port'] || process.env.UI_PORT

// And in run():
async function run() {
  const app = await loadRoutes()
  const defaultPort = devMode ? 8070 : 443
  const serverPort = UI_PORT ? parseInt(UI_PORT, 10) : defaultPort
  // ...
}

This allows configuring the admin UI port via:

  • --ui-port 8443 command line flag
  • UI_PORT=8443 environment variable

2. Update nix-bitcoin module

Once upstream supports --ui-port, update modules/lamassu-lnbits.nix:

Re-enable options

# Uncomment and update:
adminPort = mkOption {
  type = types.port;
  default = 8443;  # Internal port when nginx is used
  description = "Port for the lamassu admin UI (internal, behind nginx).";
};

nginx = {
  enable = mkEnableOption "Nginx reverse proxy on port 443";
  hostname = mkOption {
    type = types.nullOr types.str;
    default = null;
    description = "Hostname for nginx virtual host";
  };
};

Add nginx configuration

services.nginx = mkIf cfg.nginx.enable {
  enable = true;
  recommendedTlsSettings = true;
  recommendedProxySettings = true;

  virtualHosts.${cfg.nginx.hostname or cfg.hostname} = {
    forceSSL = true;
    sslCertificate = cfg.certPath;
    sslCertificateKey = cfg.keyPath;

    # Route API endpoints to main server
    locations."/ca".proxyPass = "https://127.0.0.1:${toString cfg.serverPort}";
    locations."/pair".proxyPass = "https://127.0.0.1:${toString cfg.serverPort}";

    # Route everything else to admin UI
    locations."/".proxyPass = "https://127.0.0.1:${toString cfg.adminPort}";
  };
};

Update admin server service

ExecStart = "${lamassuAdminEnv} ... lamassu-admin-server --ui-port ${toString cfg.adminPort} ...";

# Only need CAP_NET_BIND_SERVICE if adminPort < 1024 and nginx is disabled
AmbientCapabilities = optionals (cfg.adminPort < 1024 && !cfg.nginx.enable) [ "CAP_NET_BIND_SERVICE" ];

Update firewall

networking.firewall.allowedTCPPorts =
  [ cfg.serverPort ] ++
  (optional cfg.nginx.enable 443) ++
  (optional (!cfg.nginx.enable && cfg.adminPort < 1024) cfg.adminPort);

Architecture

Current (no nginx support)

                    ┌─────────────────────────────┐
    :3000 ─────────►│  lamassu-server (API)       │
                    └─────────────────────────────┘
                    ┌─────────────────────────────┐
    :443 ──────────►│  lamassu-admin-server (UI)  │
                    └─────────────────────────────┘

Future (with nginx)

                    ┌─────────────────────────────┐
    :3000 ─────────►│  lamassu-server (API)       │
                    └─────────────────────────────┘

                    ┌─────────────────────────────┐
    :443 ──────────►│  nginx                      │
                    │  ├─ /ca, /pair ──► :3000    │
                    │  └─ / ──────────► :8443     │
                    └─────────────────────────────┘
                                 │
                                 ▼
                    ┌─────────────────────────────┐
    :8443 ◄────────│  lamassu-admin-server (UI)  │
                    └─────────────────────────────┘

Benefits of Nginx

  1. Single port (443) for all HTTPS traffic
  2. Better TLS handling with nginx's recommended settings
  3. Consistent with other nix-bitcoin services (BTCPayServer, mempool, etc.)
  4. Future extensibility for rate limiting, caching, etc.

Port Conflict Note

If both nginx and lamassu-admin-server try to bind to port 443, systemd will fail to start the services. The assertion below should be added to prevent this:

assertions = [
  {
    assertion = !(cfg.nginx.enable && cfg.adminPort == 443);
    message = "Cannot use nginx with adminPort 443. Set a different adminPort (e.g., 8443).";
  }
];