Web Services

Web Services & Databases

Modern, high-performance web architecture with automated certificate management and robust database backends.

Nginx Reverse Proxy

Our web architecture uses Nginx (specifically the nginxQuic fork) as a centralized reverse proxy and SSL terminator.

Core Features

  • Protocols: Native support for HTTP/3 (QUIC) and kTLS (Kernel TLS acceleration) for maximum performance.
  • SSL/TLS: Automated certificate management via ACME (Let’s Encrypt) using DNS-01 challenges (Cloudflare).
  • Security:
    • Sinkhole: A default “deny-by-default” virtual host drops all requests using unknown hostnames or raw IPs (HTTP 444).
    • Tailscale Real-IP: Automatically restores original client IPs from Tailscale proxy headers.
  • 0-RTT: Supports TLS 1.3 Early Data to reduce connection latency.

Deployment Architecture

We typically employ a “VPN-Backend” architecture:

  1. Edge VPS (vps-pacman): Terminates public SSL and forwards traffic over Tailscale.
  2. Homelab Nodes (lab-matrix, id3-eniac): Receive traffic over encrypted Tailscale tunnels (Port 80).
  3. Internal SSL: Optional “Double TLS” can be enabled for strict environments, though Tailscale’s native WireGuard encryption is the default transport.

Troubleshooting ACME Permissions

If you encounter permission errors where Nginx cannot read certificates:

  • The nginx user is automatically added to the acme group in our modules.
  • Ensure the certificate exists in /var/lib/acme/<domain>/.

PostgreSQL Database

PostgreSQL is the primary database backend for most web services in this repository.

Declarative Lifecycle (How it works)

Unlike traditional systems that require manual CREATE DATABASE and CREATE USER commands, our setup is fully declarative via the ensures system in modules/services/dev/postgresql.nix.

  1. Definition: You define your required DB and user in the module (e.g., vaultwarden.nix or headscale.nix) using modules.services.database.postgresql.ensures.
  2. NixOS Options: This populates the standard NixOS options:
    • services.postgresql.ensureDatabases
    • services.postgresql.ensureUsers
  3. Automated Construction: At boot, the PostgreSQL Post-Start script runs automatically. It checks for the existence of the user and database. If they don’t exist, it creates them instantly with the correct ownership.
  4. Password Management: Our module extends this by automatically running ALTER USER ... WITH PASSWORD using secrets from Agenix (if passwordFile is provided), ensuring your DB is both initialized and secured without any manual steps.

Maintenance & Versions

We aim for the latest stable versions (currently PostgreSQL 18).

  • State Preservation: PostgreSQL data is stored in /var/lib/postgresql/<version>.
  • Upgrading: When upgrading the package (e.g., from 17 to 18), NixOS will NOT automatically migrate your data. You must manually run the migration scripts provided by the module.

Manually Upgrading PostgreSQL

The postgresql.nix module provides custom helper scripts in the system path:

# Example: Upgrading from 17 to 18
sudo upgrade-pg-cluster-17-18

Note: Always backup your data before running an upgrade script.

Authentication Policy

We use a “Security-First, Ease-of-Use Second” policy:

  1. Local Trust: Services defined in the ensures list are automatically granted trust access over local TCP/Unix sockets.
  2. Tailscale Trust: All traffic originating from the Tailscale/Headscale network (100.64.0.0/10) is trusted by default, allowing seamless cross-host database access.
  3. SCRAM-SHA-256: All other TCP connections require strong password authentication using SCRAM.

Service Specifics

Forgejo Mailer

Forgejo is configured to use a professional SMTP setup. By default, it uses Mailjet but can be easily pointed to your self-hosted Stalwart server.

  • Sender Address: Defaults to [email protected].
  • Customizing SMTP:
    modules.services.git.forgejo.mailer = {
      from = "[email protected]";
      host = "mail.alienzj.org"; # Point to your Stalwart server
      port = 587;
    };
  • Secrets: SMTP credential is managed via age.secrets.forgejo-smtp-pass.