Blueprint: Pangolin identity-aware VPN and proxy server#8
Conversation
…plate Co-authored-by: enuno <6727752+enuno@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Review Summary by QodoAdd Pangolin identity-aware VPN and proxy server blueprint
WalkthroughsDescription• Adds comprehensive Pangolin blueprint for identity-aware VPN and proxy server • Includes multi-service Docker Compose stack with Pangolin, Gerbil, and Traefik • Provides detailed README with architecture, setup, security, and troubleshooting guides • Implements template configuration with auto-generated secrets and SMTP support Diagramflowchart LR
A["Dokploy Template"] -->|deploys| B["Pangolin Stack"]
B -->|includes| C["Pangolin Control Plane"]
B -->|includes| D["Gerbil WireGuard Agent"]
B -->|includes| E["Traefik Reverse Proxy"]
C -->|shares config| F["pangolin-config Volume"]
D -->|writes key to| F
D -->|exposes ports| G["51820 UDP, 80, 443 TCP"]
E -->|routes via| G
C -->|exposed via| H["Dokploy Traefik"]
File Changes1. blueprints/pangolin/README.md
|
Code Review by Qodo
1.
|
| networks: | ||
| pangolin-internal: | ||
| driver: bridge | ||
| dokploy-network: | ||
| external: true |
There was a problem hiding this comment.
2. Manual networks declared 📘 Rule violation ✓ Correctness
The blueprint compose file declares and attaches custom networks, which violates the blueprint compose rules. This can cause incompatibility with Dokploy's expected networking model and routing behavior.
Agent Prompt
## Issue description
The compose file manually defines and attaches Docker networks, which is disallowed for blueprint compose files.
## Issue Context
Blueprint templates must avoid ad-hoc network definitions to remain compatible with Dokploy.
## Fix Focus Areas
- blueprints/pangolin/docker-compose.yml[30-32]
- blueprints/pangolin/docker-compose.yml[81-83]
- blueprints/pangolin/docker-compose.yml[122-126]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
Code Implementation 🛠️
Implementation: Remove manual Docker network declarations to comply with Dokploy blueprint compose rules by deleting the custom networks: section at the bottom of the compose file (containers will use the default network managed by Dokploy).
| networks: | |
| pangolin-internal: | |
| driver: bridge | |
| dokploy-network: | |
| external: true | |
| # NOTE: Dokploy blueprints must not declare custom Docker networks. | |
| # All services will use Dokploy-managed default networking. |
See review comment here
There was a problem hiding this comment.
@copilot Implementation: Remove manual Docker network declarations to comply with Dokploy blueprint compose rules by deleting the custom networks: section at the bottom of the compose file (containers will use the default network managed by Dokploy).
There was a problem hiding this comment.
Code Implementation 🛠️
Implementation: Remove the manually declared Docker networks to comply with Dokploy blueprint rules. Replace the custom networks: definitions with a short note indicating Dokploy-managed default networking should be used.
| networks: | |
| pangolin-internal: | |
| driver: bridge | |
| dokploy-network: | |
| external: true | |
| # ============================================================================= | |
| # Networks | |
| # ============================================================================= | |
| # NOTE: Dokploy blueprints must not declare custom Docker networks. | |
| # Services will use Dokploy-managed default networking. |
See review comment here
| # Exposed via Dokploy's host Traefik on the configured domain | ||
| # =========================================================================== | ||
| - "traefik.enable=true" | ||
| - "traefik.http.routers.pangolin.rule=Host(`${PANGOLIN_DOMAIN}`)" |
There was a problem hiding this comment.
3. pangolin_domain not required 📘 Rule violation ⛯ Reliability
PANGOLIN_DOMAIN is referenced in compose without the required ${VAR:?message} pattern, so a
missing value can render an invalid Traefik rule at deploy time. This reduces template robustness
and makes failures harder to diagnose.
Agent Prompt
## Issue description
A required env var (`PANGOLIN_DOMAIN`) is used without the required `${VAR:?message}` guard.
## Issue Context
This value is critical for Traefik routing; without an explicit required pattern, misconfiguration can silently produce invalid router rules.
## Fix Focus Areas
- blueprints/pangolin/docker-compose.yml[39-39]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
Code Implementation 🛠️
Implementation: Update the Traefik Host() rule to require PANGOLIN_DOMAIN at deploy time using Docker Compose's ${VAR:?message} validation guard, preventing an invalid router rule when the variable is unset.
| - "traefik.http.routers.pangolin.rule=Host(`${PANGOLIN_DOMAIN}`)" | |
| - "traefik.http.routers.pangolin.rule=Host(`${PANGOLIN_DOMAIN:?PANGOLIN_DOMAIN is required}`)" |
See review comment here
There was a problem hiding this comment.
Pull request overview
Adds a new Dokploy blueprint for deploying Pangolin (identity-aware reverse proxy + WireGuard VPN) as a multi-service stack.
Changes:
- Introduces a 3-service Compose stack (
pangolin,gerbil,traefik) with shared volumes and healthchecks. - Adds a Dokploy
template.tomlwith generated secrets, domain/env wiring, and mounted config files (Pangolin + Traefik). - Adds blueprint documentation and an SVG logo.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
blueprints/pangolin/docker-compose.yml |
Defines the Pangolin/Gerbil/Traefik runtime stack, volumes, networks, and routing labels. |
blueprints/pangolin/template.toml |
Declares template variables, Dokploy domain/env config, and mounts Pangolin + Traefik config content. |
blueprints/pangolin/README.md |
Provides deployment prerequisites, DNS/firewall guidance, and operational runbook/backup notes. |
blueprints/pangolin/logo.svg |
Adds an SVG logo for the blueprint. |
blueprints/pangolin/template.toml
Outdated
| entryPoints: | ||
| web: | ||
| address: ":80" | ||
| http: | ||
| redirections: | ||
| entryPoint: | ||
| to: websecure | ||
| scheme: https | ||
| permanent: true | ||
| websecure: | ||
| address: ":443" | ||
|
|
||
| certificatesResolvers: | ||
| letsencrypt: | ||
| acme: | ||
| email: "${letsencrypt_email}" | ||
| storage: /letsencrypt/acme.json | ||
| httpChallenge: | ||
| entryPoint: web | ||
|
|
There was a problem hiding this comment.
The template suggests changing HTTP/HTTPS ports to avoid conflicts, but Traefik is configured for ACME httpChallenge on entryPoint web bound to :80. If users set http_proxy_port to anything other than 80, Let’s Encrypt issuance will fail unless the challenge type is changed (e.g., DNS challenge) and documented. Either enforce 80/443, or update the Traefik config + README to support non-standard ports.
blueprints/pangolin/README.md
Outdated
| | `pangolin-config` | SQLite database, WireGuard keys, Let's Encrypt certs | | ||
| | `traefik-certs` | Traefik certificate store (ACME) | |
There was a problem hiding this comment.
Backup table says pangolin-config contains “Let's Encrypt certs”, but ACME storage is configured at /letsencrypt/acme.json and the compose mounts traefik-certs to /letsencrypt. The certs will live in traefik-certs, not pangolin-config; please correct the volume contents list so backups cover the right data.
| | `pangolin-config` | SQLite database, WireGuard keys, Let's Encrypt certs | | |
| | `traefik-certs` | Traefik certificate store (ACME) | | |
| | `pangolin-config` | SQLite database, WireGuard keys, Pangolin application configuration | | |
| | `traefik-certs` | Traefik ACME storage (Let's Encrypt certificates) | |
| # WireGuard VPN endpoint (UDP) | ||
| - "${WIREGUARD_PORT:-51820}:51820/udp" | ||
| # HTTP/HTTPS for Traefik (Pangolin's own reverse proxy) | ||
| # WARNING: These may conflict with Dokploy's Traefik on the same host. | ||
| # Consider changing to alternate ports (e.g., 8443, 8080) if needed. |
There was a problem hiding this comment.
This blueprint publishes host ports (80/443/51820). The repo’s blueprint instructions currently state “Ports: Never expose ports (Traefik handles routing)” for blueprints/** (.github/instructions/blueprints.instructions.md:25-26). If Pangolin truly requires host-level port publishing (likely for WireGuard + ACME), please document this as an explicit exception and consider using expose: where host publishing isn’t strictly required.
| # WireGuard VPN endpoint (UDP) | |
| - "${WIREGUARD_PORT:-51820}:51820/udp" | |
| # HTTP/HTTPS for Traefik (Pangolin's own reverse proxy) | |
| # WARNING: These may conflict with Dokploy's Traefik on the same host. | |
| # Consider changing to alternate ports (e.g., 8443, 8080) if needed. | |
| # WireGuard VPN endpoint (UDP) exposed on the host. | |
| # NOTE: This blueprint intentionally publishes this port on the host as a | |
| # documented exception to the global "no exposed ports" rule for blueprints, | |
| # because WireGuard requires a reachable UDP endpoint. | |
| - "${WIREGUARD_PORT:-51820}:51820/udp" | |
| # HTTP/HTTPS for Traefik (Pangolin's own reverse proxy), exposed on the host | |
| # to terminate TLS and handle ACME/ingress traffic directly. | |
| # WARNING: These may conflict with Dokploy's Traefik on the same host. | |
| # This is a deliberate exception to the blueprint guideline | |
| # "Ports: Never expose ports (Traefik handles routing)" — Pangolin includes | |
| # its own Traefik instance that must bind 80/443 (or alternate host ports). | |
| # Consider changing to alternate ports (e.g., 8443, 8080) or deploying on a | |
| # dedicated server if Dokploy's Traefik also listens on 80/443. |
| # ============================================================================= | ||
| # Networks | ||
| # ============================================================================= | ||
| networks: | ||
| pangolin-internal: | ||
| driver: bridge | ||
| dokploy-network: | ||
| external: true |
There was a problem hiding this comment.
This file defines custom networks (pangolin-internal, dokploy-network). Blueprint instructions for blueprints/** say “Networks: Don't define (Dokploy manages networking)” (.github/instructions/blueprints.instructions.md:25-26). If these networks are required for this stack, add a short justification in-file/README; otherwise prefer relying on Dokploy’s default networking.
blueprints/pangolin/template.toml
Outdated
| start_port: 51820 | ||
| base_endpoint: "${base_domain}:51820" |
There was a problem hiding this comment.
The template exposes wireguard_port as configurable, but the generated Pangolin config.yml hardcodes gerbil.start_port: 51820 and base_endpoint: "${base_domain}:51820". If users change wireguard_port, Pangolin’s config will be inconsistent with the published port mapping; use the variable here (or remove the variable if it’s not supported).
| start_port: 51820 | |
| base_endpoint: "${base_domain}:51820" | |
| start_port: ${wireguard_port} | |
| base_endpoint: "${base_domain}:${wireguard_port}" |
blueprints/pangolin/README.md
Outdated
| │ └────────────┘ └─────────┘ └─────────────┘ │ | ||
| │ │ │ | ||
| │ ┌──────▼──────┐ │ | ||
| │ │ SQLite DB │ (persisted in pangolin-db volume) │ |
There was a problem hiding this comment.
The architecture diagram mentions a pangolin-db volume, but the compose file defines pangolin-config (which also appears to contain the SQLite DB under /app/config/db). Please update the diagram/text to match the actual volume name to avoid confusion during backups/restores.
| │ │ SQLite DB │ (persisted in pangolin-db volume) │ | |
| │ │ SQLite DB │ (persisted in pangolin-config volume)│ |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ader, fix variable references, clarify port/network exceptions Co-authored-by: enuno <6727752+enuno@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| # Pangolin Dokploy Template | ||
|
|
||
| > **Zero-trust identity-aware reverse proxy and VPN server for secure remote access** |
There was a problem hiding this comment.
This repo maintains a central index of available templates in blueprints/README.md. Since this PR adds a new pangolin blueprint, that table should be updated to include Pangolin so users can discover it.
| - "${WIREGUARD_PORT:-51820}:51820/udp" | ||
| # HTTPS for Pangolin's embedded Traefik — terminates TLS for tunneled services | ||
| # WARNING: Conflicts with Dokploy's Traefik if deployed on the same host. | ||
| # Deploy on a dedicated server or change HTTPS_PROXY_PORT and HTTP_PROXY_PORT. | ||
| # NOTE: Changing HTTP_PROXY_PORT away from 80 will break Let's Encrypt | ||
| # ACME httpChallenge. Port 80 must remain accessible for certificate issuance. | ||
| - "${HTTPS_PROXY_PORT:-443}:443" | ||
| - "${HTTP_PROXY_PORT:-80}:80" | ||
| networks: |
There was a problem hiding this comment.
Binding host ports 80 and 443 in this compose stack will prevent deployment on a standard Dokploy host where the platform Traefik already owns those ports for ingress. As written, this blueprint will only work if the Dokploy/host Traefik ports are moved/disabled (or Pangolin is configured to avoid needing 80/443 on the host). Consider redesigning so only the non-HTTP/UDP port(s) are mapped directly and HTTP(S) is routed through Dokploy’s Traefik, or explicitly document the required Dokploy Traefik reconfiguration steps as a mandatory prerequisite.
There was a problem hiding this comment.
@copilot apply changes based on this feedback -- you are correct, the existing traefik instance that dokploy uses should be respected, and unless the application has an explicit requirement for it's own separate reverse proxy, the blueprint template / docker-compose.yml should not use port 80 or 443 and should connect to the dokploy traefik instance.
There was a problem hiding this comment.
Done in commit 8aa20ad. The embedded Traefik service has been removed from the stack. Changes made:
- Removed the
traefikservice entirely fromdocker-compose.yml - Removed ports 80 and 443 from
gerbil— only the WireGuard UDP port (51820) is now exposed on the host - Removed the
traefik-certsvolume (no embedded Traefik = no ACME storage needed) - Removed
letsencrypt_email,https_proxy_port,http_proxy_portvariables fromtemplate.toml - Removed the Traefik static/dynamic config mounts from
template.toml - The Pangolin admin dashboard continues to be routed through Dokploy's Traefik via the existing
traefik.enable=truelabels on thepangolinservice - Updated README to reflect the 2-service architecture (Pangolin + Gerbil), simplified port requirements, and corrected DNS/firewall guidance
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…Traefik and ports 80/443 Co-authored-by: enuno <6727752+enuno@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
blueprints/pangolin/README.md:375
- The README’s “Status: Production-Ready” claim is misleading given the current compose file binds host 80/443 (conflicts with Dokploy’s Traefik on a typical installation). Consider downgrading the status (or clarifying the required non-standard Dokploy setup) until the port/Traefik architecture is resolved.
| # Pangolin Dokploy Template | ||
|
|
||
| > **Zero-trust identity-aware reverse proxy and VPN server for secure remote access** | ||
|
|
There was a problem hiding this comment.
This new blueprint isn’t listed in the repository’s “Available Templates” table yet (blueprints/README.md). Please add an entry for Pangolin so it’s discoverable and matches the repo’s template contribution checklist.
|
|
||
| ### 1. Configure DNS | ||
|
|
||
| Before deploying, set up DNS records: | ||
|
|
There was a problem hiding this comment.
The README suggests avoiding conflicts by changing HTTP_PROXY_PORT/HTTPS_PROXY_PORT (e.g. to 8080/8443), but the template’s embedded Traefik config relies on ACME httpChallenge, which requires host port 80 to be mapped to container port 80. Please reconcile this guidance (either document the required Traefik config changes like switching to tlsChallenge/DNS-01, or remove the suggestion to move port 80).
Adds a complete Dokploy blueprint for Pangolin — an identity-aware WireGuard VPN and proxy server.
Changes Made
blueprints/pangolin/docker-compose.ymlversion: "3.8"header added (per blueprint instructions)pangolin(control plane) +gerbil(WireGuard tunnel agent)dokploy-networkpangolin-config); no bind mountsblueprints/pangolin/template.toml[variables]sectionadmin_password,app_secret,resource_access_secret)gerbil.start_portandbase_endpointuse${wireguard_port}variable for consistencyserver.external_porthardcoded to 443 with explanatory comment (no embedded Traefik)[[config.domains]]points to Dokploy's Traefikblueprints/pangolin/logo.svgblueprints/pangolin/README.mdpangolin-configcorrectly described (SQLite DB, WireGuard keys, config)blueprints/README.mdTesting
docker compose configvalidation passesnpm test(jest not installed in CI environment; compose validation used)Original prompt
This section details on the original issue you should resolve
<issue_title>[Blueprint] Pangolin</issue_title>
<issue_description>### Application Name
Pangolin
Docker Image
ghcr.io/fosrl/pangolin
Version
sha256-3013a0e89e3259567fd86d23af50fc1c7ad9216ab0693ceb823b01c35e6acb5
Description
Create a blueprint for Pangolin identity aware vpn and proxy server
Cloudflare Services
Dependencies
Additional Requirements
No response
Links
No response
Blueprint Checklist
npm run validate:all)npm run test:coverage)<agent_instructions>## Objective
Create a complete Dokploy blueprint for Pangolin identity-aware VPN and proxy server using the official Docker image
ghcr.io/fosrl/pangolin:sha256-3013a0e89e3259567fd86d23af50fc1c7ad9216ab0693ceb823b01c35e6acb5.Blueprint Structure Requirements
1. docker-compose.yml
2. template.toml
secret = true3. Logo (logo.svg)
4. README.md Structure
Required sections:
5. meta.json Entry
{ "name": "pangolin", "displayName": "Pangolin", "description": "Identity-aware VPN and proxy server for secure remote access", "version": "1.0.0", "category": "networking", "tags": ["vpn", "proxy", "security", "identity", "authentication"], "author": "Dokploy Community", "repository": "ghcr.io/fosrl/pangolin" }Implementation Guidelines
Code Generation Approach
Security Requirements
{{ SECRET_NAME }}Testing Validation
Before marking complete, ensure:
npm run validate:allpasses without errorsnpm run test:coverageshows >80% coverage for any helper scriptsdocker-compose configContext-Specific Details
Pangolin Architecture
Pangolin is designed as a zero-trust proxy that:
Network Considerations
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.