Securing Pangolin + Newt with Multi-Network Docker Stacks

Securing Pangolin + Newt with Multi-Network Docker Stacks

When running Pangolin with Newt, it’s tempting to throw all your containers onto the same pangolin network for convenience. But that creates a flat trust model: any container on that network inherits Pangolin’s reachability into your LAN via Newt.

This guide shows how to segment your containers with multiple Docker networks so only the services that truly need WAN/LAN access touch Pangolin.

I have taken pangolin as default e.g, but same goes for NEWT.


Why Flat Networking is Risky

  • Newt extends trust: Newt bridges the Pangolin host into your LAN subnet. Any container on the Pangolin network can potentially reach your LAN.
  • One compromise = full access: If an exposed service (say, a web app) is compromised, an attacker could pivot into your LAN or other containers.
  • Databases and admin tools at risk: Putting Postgres, Portainer, or other sensitive services on the Pangolin network unnecessarily exposes them.

The Safer Pattern: Multi-Network Segmentation

Docker lets you attach a container to multiple networks. Use this to separate:

  • Internal stack communication (e.g., app ↔ database).
  • External exposure (only the app container touches Pangolin).

Example docker-compose.yml

services:
  app:
    image: my-app-image:latest
    networks:
      - stack-net     # internal comms
      - pangolin      # external exposure via Pangolin/Newt

  database:
    image: postgres:15
    networks:
      - stack-net     # isolated, no Pangolin/Newt access

networks:
  stack-net:
    driver: bridge
  pangolin:
    external: true

Bad vs Good: Flat vs Segmented Networking

Bad: Flat Networking (All on Pangolin/Newt)

services:
  app:
    image: my-app-image:latest
    networks:
      - pangolin

  database:
    image: postgres:15
    networks:
      - pangolin   # ❌ DB exposed to Pangolin/Newt + LAN

  portainer:
    image: portainer/portainer-ce
    networks:
      - pangolin   # ❌ Admin tool exposed to Pangolin/Newt + LAN

networks:
  pangolin:
    external: true

Problems:

  • Database and admin tools are directly reachable from Pangolin and potentially your LAN via Newt.
  • Any compromise in app could pivot into DB or Portainer.
  • Flat trust model: one weak link = LAN exposure.

Good: Segmented Networking (Internal + Pangolin)

services:
  app:
    image: my-app-image:latest
    networks:
      - stack-net     # internal comms
      - pangolin      # external exposure via Pangolin/Newt

  database:
    image: postgres:15
    networks:
      - stack-net     # ✅ isolated, only app can reach it

  portainer:
    image: portainer/portainer-ce
    networks:
      - stack-net     # ✅ internal only, access via VPN/SSH tunnel

networks:
  stack-net:
    driver: bridge
  pangolin:
    external: true

Benefits:

  • Database is isolated on stack-net, only reachable by the app.
  • Portainer stays internal, accessible only through secure tunnels (VPN, SSH).
  • Only the app container touches Pangolin, enforcing least privilege.

Security Breakdown

Scenario Risk if on Pangolin/Newt net Safer with Multi-Network
Database Directly reachable from Pangolin host and LAN. Only on stack-net, app mediates access.
Admin tools (Portainer, etc.) Exposed to Pangolin + LAN. Weak creds = takeover. Keep on stack-net, access via VPN/SSH tunnel.
Flat trust model Any container compromise = LAN compromise. Segmentation enforces least privilege.

:white_check_mark::cross_mark: Checklist: What Should / Shouldn’t Be on Pangolin Net

:white_check_mark: Safe to Attach

  • Public-facing apps (web apps, APIs, dashboards)
  • Reverse proxies / ingress controllers (Traefik, Caddy, Nginx)
  • Authentication / identity services that validate external requests
  • Monitoring endpoints you explicitly want exposed

:cross_mark: Keep OFF

  • Databases (Postgres, MySQL, MongoDB, Redis, etc.)
  • Admin tools (Portainer, phpMyAdmin, pgAdmin, Grafana, etc.)
  • Internal-only services (workers, queues, cron jobs)
  • Secrets managers (Vault, Keycloak DB backends, etc.)
  • Anything with weak or no authentication

Case-by-Case

  • Update services / mirrors → usually internal
  • Metrics exporters → internal unless intentionally exposed
  • CI/CD runners → safer internal, expose only via VPN/SSH

Rule of Thumb:

  • Needs outside access → Pangolin.
  • Internal-only → stack-net.
  • Unsure → default to internal.

Visual Diagram

ASCII (works everywhere)

                ┌───────────────────────────────┐
                │           Internet            │
                └───────────────▲───────────────┘
                                │
                        ┌───────┴───────┐
                        │   Pangolin    │
                        │ (external net)│
                        └───────┬───────┘
                                │
                ┌───────────────┼────────────────┐
                │               │                │
        ┌───────▼───────┐ ┌─────▼───────┐ ┌─────▼───────┐
        │     App       │ │  Database   │ │  Portainer  │
        │ (stack-net +  │ │ (stack-net) │ │ (stack-net) │
        │  pangolin)    │ │             │ │             │
        └───────┬───────┘ └─────────────┘ └─────────────┘
                │
        ┌───────▼───────┐
        │   stack-net   │  (internal-only bridge)
        └───────────────┘

Key Takeaway

The real danger isn’t just “a service on the same Docker network as Pangolin.”
It’s that Newt extends Pangolin’s host into your LAN, so any container on Pangolin’s network inherits that trust.

By splitting into internal vs external networks, you enforce least privilege and prevent lateral movement from an exposed service into your LAN.


References


1 Like

Great piece of information.

1 Like

Do you need to create the network before running?

1 Like

I gave that a try using this config with the pangolin #commented out and I get bad gateway, it works with just the pangolin network.

#version: '3.8'
    services:
      portainer:
        image: portainer/portainer-ce:2.33.2
        container_name: portainer
        ports:
          - "9443:9443"
          - "9000:9000" # Or 9443:9443 for HTTPS
        volumes:
          - portainer_data:/data
          - /var/run/docker.sock:/var/run/docker.sock
        restart: unless-stopped
        networks:
          - pangolin
          #- stack-net

    volumes:
      portainer_data:

    networks:
      #stack-net:
        #driver: bridge
      pangolin:
        external: true
1 Like

“bad gateway” is newt in the stack-net? or newt is in pangolin(network) only? If you have newt in pangolin(network) you will have to either move newt to the stack-net or add stack-net to newt. I am assuming you are running portainer on a remote host and accessing it over newt.

1 Like

I have portainer added to the resources tab that points to my home server this is a container on the vps using local site in resources.

1 Like

:cross_mark: Keep OFF

  • Anything with weak or no authentication

Isn’t it one of the advantages of Pangolin that you can put it in front of an app that has weak or no authentication and use the Pangolin authentication to control access?

I want to start using OICD where apps support it, but for those that don’t, am I able to rely on the Pangolin auth to at least provide some security?

Example:
Sonarr provide a login but doesn’t support OAuth/OIDC. Can I turn off the Sonarr auth because it’s proxied by Pangolin? - I have to login to Pangolin and there are rules that control who can access Sonarr through Pangolin.

1 Like

Yes. If you add OIDC it will show when Auth is enabled. Like this

1 Like