AI Gateway is now available: identity-aware access to any AI provider, eliminate API keys, and tunnel to self-hosted models. Get started

Docker Compose

Deploy managed Pangolin manually using Docker Compose without the automated installer

This guide is for managed self-hosted Pangolin. If you are looking for self-hosted Community Edition Pangolin please see this Docker Compose guide.

This guide walks you through setting up Pangolin manually using Docker Compose without the automated installer. This approach gives you full control over the configuration and deployment process.

This guide assumes you already have a Linux server with Docker and Docker Compose installed. If you don't, please refer to the official Docker documentation for installation instructions. You must also have root access to the server.

Prerequisites

Checkout the quick install guide for more info regarding what is needed before you install Pangolin.

File Structure

Create the following directory structure for your Pangolin deployment:

.
├── config/
│   ├── config.yml (*)
│   ├── db/
│   │   └── db.sqlite
│   ├── key
│   └── traefik/
│       ├── traefik_config.yml (*)
└── docker-compose.yml (*)

Files marked with (*) must be created manually. Volumes and other files are generated automatically by the services.

Configuration Files

config/config.yml: Main Pangolin configuration file

config/traefik/traefik_config.yml: Traefik static configuration

  • Global Traefik settings and entry points
Generated Files

config/db/db.sqlite: SQLite database file

  • Created automatically on first startup
  • Contains all Pangolin data and settings

config/key: Private key file

  • Generated by Gerbil service
  • Used for WireGuard tunnel encryption
Docker Files

docker-compose.yml: Service definitions

  • Defines Pangolin, Gerbil, and Traefik services
  • Network configuration and volume mounts
  • Health checks and dependencies

Create configuration directory

mkdir -p config/traefik config/db

Create configuration files

Create the main configuration files (see below):

  • docker-compose.yml (in project root)
  • config/traefik/traefik_config.yml
  • config/config.yml

Update domain

Edit the configuration files to replace:

  • 154.123.45.67 with your actual domain OR public IP address of the node

Ensure your domain DNS is properly configured to point to your server's IP address if you choose DNS.

Starting the Stack

Start the services

sudo docker compose up -d

Monitor startup

sudo docker compose logs -f

Verify services

sudo docker compose ps

All services should show "Up" status after a few minutes.

Docker Compose Configuration

Create docker-compose.yml in your project root:

docker-compose.yml
services:
  pangolin:
    image: fosrl/pangolin:latest # https://github.com/fosrl/pangolin/releases
    container_name: pangolin
    restart: unless-stopped
    volumes:
      - ./config:/app/config
      - pangolin-data:/var/certificates
      - pangolin-data:/var/dynamic
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "3s"
      timeout: "3s"
      retries: 15

  gerbil:
    image: fosrl/gerbil:latest # https://github.com/fosrl/gerbil/releases
    container_name: gerbil
    restart: unless-stopped
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --reachableAt=http://gerbil:3004
      - --generateAndSaveKeyTo=/var/config/key
      - --remoteConfig=http://pangolin:3001/api/v1/
    volumes:
      - ./config/:/var/config
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    ports:
      - 51820:51820/udp
      - 21820:21820/udp
      - 443:8443
      - 80:80

  traefik:
    image: traefik:v3.7
    container_name: traefik
    restart: unless-stopped
    network_mode: service:gerbil # Ports appear on the gerbil service
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    volumes:
      - ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
      - ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
      # Shared volume for certificates and dynamic config in file mode
      - pangolin-data:/var/certificates:ro
      - pangolin-data:/var/dynamic:ro

networks:
  default:
    driver: bridge
    name: pangolin

volumes:
  pangolin-data:

Traefik Static Configuration

Create config/traefik/traefik_config.yml:

config/traefik/traefik_config.yml
api:
  insecure: true
  dashboard: true

providers:
  file:
    directory: "/var/dynamic"
    watch: true

experimental:
  plugins:
    badger:
      moduleName: "github.com/fosrl/badger"
      version: "v1.4.1"

log:
  level: "INFO"
  format: "common"

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    proxyProtocol:
      trustedIPs:
        - 0.0.0.0/0
        - ::1/128
    transport:
      respondingTimeouts:
        readTimeout: "30m"

serversTransport:
  insecureSkipVerify: true

ping:
    entryPoint: "web"

Pangolin Configuration

config/config.yml
gerbil:
    start_port: 51820
    base_endpoint: "154.123.45.67" # REPLACE WITH YOUR IP OR DOMAIN

managed:
    id: "he4g78wevj25msf"
    secret: "n7sd18twfko0q0vrb7wyclqzbvvnx1fqt7ezv8xewhdb9s7d"
⌘I

On this page