Home Lab project
Pangolin Reverse Proxy
Personal

Pangolin Reverse Proxy

Aug 2025
Table of Contents

Overview

Pangolin is the secure, high-availability gateway for my Proxmox Homelab. Hosted on Oracle Cloud Infrastructure (OCI), it serves as the public entry point for my publically exposed self-hosted services.

Pangolin is more than just a reverse proxy; it is an Identity-Aware Tunneled Reverse Proxy. It acts as a central hub that connects my isolated homelab network—sitting behind a restrictive residential firewall—to the public internet through encrypted tunnels. This enables me to expose services securely without opening any ports on my home router or requiring a traditional VPN for every client.

Tech Stack

TechnologyDescription
OCIOracle Cloud Infrastructure. Used as a public entry point for homelab services.
PangolinIdentity-aware access control and tunnel management.
TraefikThe edge router handling SSL termination and traffic routing on CloudVM.
CaddyLocal reverse proxy for internal routing and service discovery.
CrowdSecCollaborative Intrusion Prevention System (IPS) for threat detection.
GerbilWireGuard-based tunnel server.
TailscaleZero config VPN for secure private networking between devices.
GoAccessReal-time web log analyzer.
Ubuntu ServerThe base operating system for all Virtual Machines and LXC containers.
TerraformInfrastructure as Code tool used to provision VMs and LXC containers.
Cloud-InitIndustry standard for early initialization of cloud instances (Ubuntu Server).
DockerPlatform for developing, shipping, and running applications in containers.
CloudflareDNS management for deployed services.

Architecture

The system is built on a Secure Cloud Gateway architecture. It uses the OCI instance as a public entry point, connecting to my homelab via a secure WireGuard tunnel. This setup allows me to expose services without revealing my home IP address or opening any ports on my local router.

Reverse Proxy Architecture

1. Cloud Gateway (OCI)

Infrastructure (IaC)

The underlying infrastructure is provisioned on OCI using Terraform. This setup includes a dedicated Virtual Cloud Network (VCN), a public Subnet, and an Internet Gateway to allow external traffic to reach the proxy.

I use an oci-instances.auto.tfvars file to configure the instance resources using a map-based approach, allowing for easy expansion.

# Networking Configuration
vcn_name    = "pangolin-vcn"
vcn_cidr    = "10.0.0.0/16"
subnet_cidr = "10.0.1.0/24"

# Define instances in a structured map
oci_instances = {
  "pangolin-gateway" = {
    shape            = "VM.Standard.A1.Flex"
    ocpus            = 1
    memory_in_gbs    = 4
    assign_public_ip = true
  }
}terraform/.../oci-instances.auto.tfvars

The main.tf file defines the actual resources:

# 1. Virtual Cloud Network (VCN)
resource "oci_core_vcn" "main" {
  cidr_blocks  = [var.vcn_cidr]
  display_name = var.vcn_name
  dns_label    = "vcn"
}

# 2. Internet Gateway (for public access)
resource "oci_core_internet_gateway" "main" {
  vcn_id       = oci_core_vcn.main.id
  display_name = "${var.vcn_name}-gateway"
}

# 3. Public Subnet
resource "oci_core_subnet" "public" {
  cidr_block     = var.subnet_cidr
  vcn_id         = oci_core_vcn.main.id
  display_name   = "${var.vcn_name}-public-subnet"
}

# 4. Compute Instances (Iterate over map)
resource "oci_core_instance" "gateway_nodes" {
  for_each = var.oci_instances

  display_name = each.key
  shape        = each.value.shape

  shape_config {
    ocpus         = each.value.ocpus
    memory_in_gbs = each.value.memory_in_gbs
  }

  create_vnic_details {
    subnet_id        = oci_core_subnet.public.id
    assign_public_ip = each.value.assign_public_ip
    # ...
  }
}terraform/services/oci-gateway/main.tf

Stack (Docker Compose)

The application stack is composed of several key components running in Docker:

  1. Pangolin (Control Plane): The central dashboard and management server. It handles identity-aware access control and manages the configuration for the proxy.
  2. Gerbil (Tunnel Server): A Wireguard-based tunneling server. It listens for connections from my homelab and establishes the secure data plane.
  3. Traefik: The edge router handling SSL termination (Let’s Encrypt) and traffic routing. It polls Pangolin for dynamic configuration.
  4. CrowdSec: A collaborative IPS (Intrusion Prevention System) that analyzes logs and blocks malicious IPs.
services:
  pangolin:
    image: docker.io/fosrl/pangolin:1.11.1
    # ... healthchecks and volumes ...

  gerbil:
    image: docker.io/fosrl/gerbil:1.2.2
    cap_add:
      - NET_ADMIN
    depends_on:
      pangolin:
        condition: service_healthy
    # ...

  traefik:
    image: docker.io/traefik:v3.5
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    network_mode: service:gerbil # Routes traffic through the tunnel
    # ...docker-services/.../docker-compose.yml

2. Local Landing Zone (Public Playground)

The Public Playground Server is the designated VM in my homelab that receives traffic from the cloud. It is the only place where public traffic is allowed to enter the private network.

GoAccess Dashboard

GoAccess Dashboard

Stack (Docker Compose)

services:
  caddy:
    image: caddy:2-alpine
    # ... ports and volumes ...

  goaccess:
    image: allinurl/goaccess:latest
    command: /logs/access.log --log-format=CADDY --real-time-html ...
    volumes:
      - ./data/logs:/logs:ro
      - ./data/goaccess_report:/report:rw
    # ...docker-services/.../compose.yml

This separation ensures that even if the Public Playground is compromised, the rest of the homelab remains isolated behind internal firewalls.

Key Features

1. Tunneled Access with Newt

The connection between the OCI Gateway and my Homelab is bridged by Newt, the client-side agent.

Newt establishes an outbound encrypted tunnel to Gerbil. This allows Pangolin to route public traffic down the tunnel to my private services, bypassing NAT and firewalls entirely.

Once traffic reaches the Public Playground Server, it is handled by Caddy, which acts as the local reverse proxy. Caddy terminates the tunnel traffic and routes requests to the appropriate internal Docker services (like Yoroshiku) or other VMs in the homelab. This tiered proxy architecture ensures that:

  1. Pangolin (Cloud) handles public ingress, SSL, and security filtering.
  2. Caddy (Local) handles internal routing and service discovery within the homelab.

2. Identity & Context Aware Access

Pangolin provides a centralized dashboard to manage access policies. I can define rules based on user identity (via OIDC/OAuth) and context, ensuring that sensitive internal tools are protected by a login screen even if they don’t have built-in authentication.

3. Security First with CrowdSec

Security is paramount for a public gateway. CrowdSec reads Traefik’s access logs in real-time and detects attacks (like brute force, port scans, or HTTP probing).

experimental:
  plugins:
    crowdsec:
      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
      version: v1.4.4

entryPoints:
  websecure:
    http:
      middlewares:
        - crowdsec@file # Applied globally to all HTTPS trafficconfig/traefik/traefik_config.yml

Related Projects

    Mike 3.0

    Send a message to start the chat!

    You can ask the bot anything about me and it will help to find the relevant information!

    Try asking: