Tag: NPM

  • Setting Up Nginx Proxy Manager on a Proxmox and OPNsense Homelab

    Nginx Proxy Manager (NPM) is going to act as the reverse proxy for the websites in my homelab.

    The goal is to eventually have traffic flow like this:

    Internet
       ↓
    Cloudflare DNS
       ↓
    Public IP
       ↓
    OPNsense
       ↓
    Nginx Proxy Manager
       ↓
    Correct website/server
    

    This guide covers the initial network preparation, creation of the NPM container, installation of Docker, and deployment of Nginx Proxy Manager.

    The configuration is deliberately kept fairly simple at this stage. More advanced firewall restrictions, Cloudflare configuration, SSL certificates and website proxy hosts will be covered later.


    Homelab Network Design

    The lab is running on Proxmox with OPNsense providing routing, firewalling and VLAN management.

    Two VLANs are being used for the web-hosting environment.

    VLAN 10 — Management / Infrastructure

    Network: 192.168.10.0/24
    Gateway: 192.168.10.1
    

    This VLAN is intended for infrastructure and management services, including:

    • Nginx Proxy Manager
    • WireGuard
    • Monitoring
    • Other management services

    VLAN 20 — Websites

    Network: 192.168.20.0/24
    Gateway: 192.168.20.1
    

    This VLAN will contain the actual website workloads, including:

    • Manual LEMP installation
    • CloudPanel
    • Coolify
    • WordPress sites

    Keeping the reverse proxy and website workloads separated gives us a cleaner foundation for firewall rules and segmentation.


    Preparing OPNsense

    The Proxmox internal bridge is configured as a VLAN-aware bridge.

    The OPNsense VM has a virtual network adapter connected to this bridge and is configured as a VLAN trunk.

    The trunk currently carries:

    VLAN 10
    VLAN 20
    

    Inside OPNsense, the VLANs were created on the internal interface.

    VLAN 10

    Parent: vtnet1
    Tag: 10
    Description: MGMT
    

    VLAN 20

    Parent: vtnet1
    Tag: 20
    Description: WEB
    

    The VLAN interfaces were then assigned in OPNsense.

    MGMT

    192.168.10.1/24
    

    WEB

    192.168.20.1/24
    

    DHCP was configured for the web VLAN using Dnsmasq:

    192.168.20.100 - 192.168.20.199
    

    Static infrastructure addresses are kept outside this DHCP range.


    Firewall Considerations

    An important lesson during this setup was that firewall rules can sometimes behave differently from what initially appears obvious.

    A management rule was created to allow the MGMT network to access the Internet while preventing access to RFC1918 private networks.

    The intended logic was:

    MGMT → Internet       ALLOW
    MGMT → Private LANs   BLOCK
    

    However, the rule used an inverted RFC1918 alias.

    Because:

    192.168.10.1
    

    is itself an RFC1918 address, the rule also prevented the NPM container from reaching its own VLAN gateway.

    This initially looked like a VLAN or Proxmox networking problem.

    After checking the VLAN configuration, Proxmox bridge, virtual interfaces and OPNsense packet capture, the firewall rule was identified as the actual cause.

    This was a useful reminder:

    When troubleshooting VLAN connectivity, don’t automatically assume the VLAN is broken. Check the firewall rules as well.

    Once the rule was corrected, VLAN 10 connectivity worked as expected.


    Creating the Nginx Proxy Manager Container

    A Debian 13 LXC was created in Proxmox for Nginx Proxy Manager.

    The container was configured with:

    CT ID: 103
    Hostname: npm01
    Operating System: Debian 13
    Unprivileged: Yes
    CPU: 1 vCPU
    RAM: 1 GB
    Swap: 512 MB
    Disk: 8 GB
    Nesting: Enabled
    

    The container was connected to VLAN 10.

    Its network configuration was:

    IP address: 192.168.10.10/24
    Gateway: 192.168.10.1
    VLAN: 10
    

    The address is outside the DHCP range and is therefore being used as a static infrastructure address.


    Installing Docker

    Nginx Proxy Manager will run as a Docker container.

    First, the Docker repository signing key was downloaded:

    curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
    

    The key permissions were then corrected:

    chmod a+r /etc/apt/keyrings/docker.asc
    

    The official Docker repository was added:

    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      tee /etc/apt/sources.list.d/docker.list > /dev/null
    

    The package lists were updated:

    apt update
    

    Docker and the required components were installed:

    apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    

    In this particular installation, the packages were already at their newest versions.


    Verifying Docker

    Docker was checked with:

    systemctl status docker --no-pager
    

    The important result was:

    Active: active (running)
    

    Docker was also enabled to start automatically with the system.

    Docker Compose was then checked:

    docker compose version
    

    The installed version was:

    Docker Compose 5.5.1
    

    At this point Docker and Docker Compose were ready.


    Creating the NPM Directory

    A dedicated directory was created for Nginx Proxy Manager:

    mkdir -p /opt/npm
    cd /opt/npm
    

    This keeps the NPM configuration and persistent data together rather than scattering files around the system.


    Creating the Docker Compose File

    The Docker Compose file was created:

    nano /opt/npm/docker-compose.yml
    

    The following configuration was used:

    services:
      app:
        image: 'jc21/nginx-proxy-manager:latest'
        container_name: nginx-proxy-manager
        restart: unless-stopped
        ports:
          - '80:80'
          - '81:81'
          - '443:443'
        volumes:
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt
    

    The important ports are:

    80   HTTP
    81   NPM administration interface
    443  HTTPS
    

    The two volume mappings ensure that NPM’s application data and Let’s Encrypt certificates are stored outside the container filesystem.

    This means the container can be recreated without automatically losing the persistent NPM data.


    Starting Nginx Proxy Manager

    From /opt/npm, NPM was started with:

    cd /opt/npm
    docker compose up -d
    

    Docker downloaded the Nginx Proxy Manager image and created the Docker network and container.

    The result included:

    Image jc21/nginx-proxy-manager:latest Pulled
    Network npm_default Created
    Container nginx-proxy-manager Started
    

    Checking the Container

    The running containers were checked with:

    docker ps
    

    The NPM container appeared as:

    nginx-proxy-manager
    

    and showed:

    Up
    

    The published ports were:

    0.0.0.0:80-81
    0.0.0.0:443
    

    This confirms that the container is listening for connections on the expected ports.


    Checking the NPM Logs

    Finally, the container logs were checked:

    docker logs nginx-proxy-manager --tail 30
    

    The output showed the initial database migrations completing, default settings being created, SSL renewal being initialized and the backend starting successfully.

    The important line was:

    Backend PID ... listening on port 3000
    

    No startup errors were reported.


    Current Status

    At this point the basic Nginx Proxy Manager installation is complete.

    The current layout is:

                        Internet
                           │
                           ▼
                        OPNsense
                           │
                      VLAN 10 / MGMT
                           │
                           ▼
                 ┌──────────────────┐
                 │      npm01       │
                 │                  │
                 │ Nginx Proxy      │
                 │ Manager          │
                 │                  │
                 │ 192.168.10.10   │
                 └──────────────────┘
                           │
                           │
                      Later:
                           │
                           ▼
                     VLAN 20 / WEB
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
            LEMP       CloudPanel     Coolify
    

    Nginx Proxy Manager is running successfully in its Debian 13 LXC using Docker Compose.

    The next stage will be to access the NPM administration interface, perform the initial configuration and then begin configuring it as the reverse proxy for the first website.


    What We Have Learned

    This stage provided a useful practical exercise in several areas:

    • Proxmox VLAN-aware bridges
    • VLAN trunking
    • OPNsense VLAN interfaces
    • OPNsense firewall behaviour
    • RFC1918 network restrictions
    • Debian 13 administration
    • Docker installation
    • Docker Compose
    • Persistent Docker volumes
    • Nginx Proxy Manager deployment
    • Basic container troubleshooting

    One of the most useful lessons was that a connectivity problem doesn’t necessarily mean the VLAN or virtual networking is wrong. In this case, the underlying VLAN configuration was working; the firewall rule was preventing the expected traffic.

    That is exactly the sort of problem that makes a homelab useful for learning.