diff --git a/blueprints/README.md b/blueprints/README.md index b5c6ce5..73ed862 100644 --- a/blueprints/README.md +++ b/blueprints/README.md @@ -70,6 +70,7 @@ This directory contains custom Dokploy templates for deploying applications in t | [open-notebook](/blueprints/open-notebook/) | Private multi-model AI knowledge management platform with 16+ AI provider support | 1 (all-in-one) | Ready | | [paaster](/blueprints/paaster/) | Secure end-to-end encrypted pastebin with zero-knowledge server | 5 (paaster, mongodb, + helpers) | Ready | | [padloc](/blueprints/padloc/) | Open-source password manager with end-to-end encryption and zero-knowledge architecture | 2 (server, pwa) | Ready | +| [pangolin](/blueprints/pangolin/) | Identity-aware VPN and proxy server with WireGuard tunnels and zero-trust access control | 2 (pangolin, gerbil) | Ready | | [personalized-deep-research](/blueprints/personalized-deep-research/) | Intelligent research agent with Nuxt frontend for complex AI-powered research tasks | 1 (deep-research-web) | Ready | | [signal-cli-rest-api](/blueprints/signal-cli-rest-api/) | REST API wrapper for Signal Messenger enabling programmatic messaging with QR code device linking | 1 (signal-cli-rest-api) | Ready | | [someguy](/blueprints/someguy/) | HTTP Delegated Routing V1 server for IPFS with Amino DHT proxy | 1 (someguy) | Ready | diff --git a/blueprints/pangolin/README.md b/blueprints/pangolin/README.md new file mode 100644 index 0000000..f735774 --- /dev/null +++ b/blueprints/pangolin/README.md @@ -0,0 +1,342 @@ +# Pangolin Dokploy Template + +> **Zero-trust identity-aware reverse proxy and VPN server for secure remote access** + +- 🔐 **Identity-Aware Access**: Enforce authentication before reaching any resource +- 🌐 **WireGuard VPN Tunnels**: Connect remote sites and clients with modern WireGuard +- 👥 **Multi-Org Support**: Isolated organizations with role-based access control +- 🔑 **SSO / OIDC Integration**: Connect to Authelia, Authentik, Keycloak, and more +- 🛡️ **Zero-Trust Architecture**: No implicit trust — every request is authenticated +- 📊 **Audit Logging**: Track all access and connections + +**Official Documentation**: https://docs.pangolin.net/ + +--- + +## Architecture + +``` +Internet + │ + ├── 51820 (UDP) ──► Gerbil (WireGuard) ──► VPN Clients + │ + └── Dokploy Traefik (443/HTTPS) ──► Pangolin Dashboard (Admin UI) + +┌─────────────────────────────────────────────────────┐ +│ Pangolin Stack │ +│ │ +│ ┌────────────┐ ┌─────────┐ │ +│ │ Pangolin │◄───│ Gerbil │ │ +│ │ (Control) │ │ (VPN) │ │ +│ │ Port 3001 │ │UDP 51820│ │ +│ │ Port 3000 │ │ │ │ +│ └────────────┘ └─────────┘ │ +│ │ │ +│ ┌──────▼──────┐ │ +│ │ SQLite DB │ (persisted in pangolin-config volume)│ +│ └─────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +**Service Type**: Multi-service stack (Pangolin + Gerbil) +**Database**: Self-contained SQLite (in `/app/config/db`) +**VPN**: WireGuard via Gerbil +**Routing**: Dokploy's Traefik handles HTTPS for the admin dashboard + +--- + +## Prerequisites + +1. **Dokploy** installed and running +2. **DNS configuration**: + - `pangolin.example.com` → Server IP (admin dashboard, routed via Dokploy Traefik) + - `*.example.com` → Server IP (optional wildcard for services accessed through WireGuard tunnels) +3. **Firewall rules**: Open port `51820/udp` + +--- + +## Quick Start + +### 1. Configure DNS + +Before deploying, set up DNS records: + +``` +# Admin dashboard +pangolin.example.com A +``` + +### 2. Deploy Template + +In Dokploy: +1. Select **"Add New Template"** +2. Choose **"Pangolin"** +3. Fill in the required variables (see [Configuration](#configuration) below) +4. Deploy + +### 3. Complete Initial Setup + +Navigate to `https://pangolin.example.com/auth/initial-setup` and: +1. Confirm admin email and password +2. Configure your organization name +3. Verify DNS is working + +### 4. Create Your First Tunnel + +1. In Pangolin admin: **Sites** → **Add Site** +2. Choose **WireGuard** tunnel type +3. Follow the newt/WireGuard client setup instructions +4. Add resources behind the tunnel + +--- + +## Configuration + +### Required Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `pangolin_domain` | Admin dashboard domain | `pangolin.example.com` | +| `base_domain` | Base domain for WireGuard tunnel clients | `example.com` | +| `admin_email` | Initial admin email address | `admin@example.com` | +| `admin_password` | Initial admin password (auto-generated) | *(generated)* | +| `app_secret` | Application secret key (auto-generated) | *(generated)* | +| `resource_access_secret` | Resource token secret (auto-generated) | *(generated)* | + +### Optional Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `wireguard_port` | `51820` | WireGuard VPN UDP port | +| `smtp_host` | *(empty)* | SMTP server for email notifications | +| `smtp_port` | `587` | SMTP port | +| `smtp_username` | *(empty)* | SMTP username | +| `smtp_password` | *(empty)* | SMTP password | +| `smtp_from_email` | *(empty)* | From address for outgoing emails | +| `log_level` | `info` | Log level: `debug`, `info`, `warn`, `error` | + +### Environment Variables (Advanced) + +These are set via Dokploy's environment variable injection: + +| Variable | Description | +|----------|-------------| +| `PANGOLIN_DOMAIN` | Admin dashboard domain | +| `WIREGUARD_PORT` | WireGuard listen port | + +--- + +## Identity Provider Setup + +Pangolin supports SSO via OpenID Connect (OIDC). Configure in the admin UI under: +**Settings** → **Identity Providers** + +### Authelia + +1. In Authelia, create a new OIDC client: + ```yaml + # authelia/configuration.yml + identity_providers: + oidc: + clients: + - id: pangolin + description: Pangolin + secret: your-client-secret + public: false + authorization_policy: two_factor + redirect_uris: + - https://pangolin.example.com/api/v1/auth/oidc/callback + scopes: + - openid + - profile + - email + grant_types: + - authorization_code + ``` +2. In Pangolin admin: **Settings** → **Identity Providers** → **Add OIDC** +3. Enter: + - **Issuer URL**: `https://auth.example.com` + - **Client ID**: `pangolin` + - **Client Secret**: `your-client-secret` + +### Authentik + +1. In Authentik, create an OAuth2/OIDC provider: + - **Redirect URIs**: `https://pangolin.example.com/api/v1/auth/oidc/callback` + - **Scopes**: `openid`, `profile`, `email` +2. Create an Application linked to this provider +3. In Pangolin admin: **Settings** → **Identity Providers** → **Add OIDC** +4. Use the Authentik OIDC metadata URL + +### Keycloak + +1. In Keycloak, create a new client: + - **Client ID**: `pangolin` + - **Client Protocol**: `openid-connect` + - **Valid Redirect URIs**: `https://pangolin.example.com/api/v1/auth/oidc/callback` +2. Note the client secret from the **Credentials** tab +3. In Pangolin admin: configure OIDC with Keycloak's realm OIDC endpoint + +--- + +## Networking + +### Port Requirements + +| Port | Protocol | Purpose | Required | +|------|----------|---------|----------| +| `51820` | UDP | WireGuard VPN tunnels | Yes | + +> **Note**: The admin dashboard HTTPS traffic (port 443) is handled by Dokploy's Traefik instance. Only the WireGuard UDP port needs to be opened in the firewall. + +### Firewall Rules + +```bash +# Open WireGuard port +ufw allow 51820/udp +``` + +### DNS Setup + +Pangolin needs a domain for the admin dashboard: + +``` +# Admin dashboard (routed via Dokploy Traefik) +pangolin.example.com A +``` + +--- + +## Security Considerations + +### Credential Management + +- ✅ Admin password is auto-generated (32 characters) +- ✅ App secrets are auto-generated and stored in Dokploy +- ✅ Change admin password after first login +- ✅ Enable MFA for admin accounts + +### Network Security + +- ✅ Admin dashboard TLS handled by Dokploy's Traefik (Let's Encrypt) +- ✅ WireGuard provides end-to-end encryption for VPN tunnels +- ✅ Use firewall to restrict WireGuard port access +- ✅ Enable identity provider authentication for zero-trust access + +### Secrets Rotation + +To rotate secrets: +1. Update `app_secret` and `resource_access_secret` in Dokploy +2. Redeploy the stack +3. Users will need to log in again (sessions invalidated) + +--- + +## Troubleshooting + +### Admin Dashboard Not Loading + +```bash +# Check Pangolin is healthy +docker compose ps +docker compose logs pangolin + +# Verify Traefik routing +curl -I https://pangolin.example.com +``` + +### WireGuard Connection Fails + +```bash +# Check Gerbil is running +docker compose logs gerbil + +# Verify UDP port is open +nc -u -zv your-server-ip 51820 + +# Check WireGuard key was generated +docker compose exec gerbil ls /var/config/key +``` + +### Services Not Accessible via Tunnel + +1. Verify site is connected: Pangolin admin → **Sites** → check status +2. Check resource configuration: correct target URL +3. Review access policies: user has permission to access resource + +--- + +## Backup + +### Critical Data + +Back up this named volume regularly: + +| Volume | Contents | +|--------|----------| +| `pangolin-config` | SQLite database, WireGuard keys, Pangolin application configuration | + +```bash +# Example backup command for pangolin config volume +docker run --rm \ + -v pangolin-config:/source:ro \ + -v /backup:/backup \ + alpine tar czf /backup/pangolin-config-$(date +%Y%m%d).tar.gz -C /source . +``` + +--- + +## Updating + +To update Pangolin: +1. Check the [Pangolin releases page](https://github.com/fosrl/pangolin/releases) +2. Update the image reference in `docker-compose.yml` +3. Also update `gerbil` image to the compatible version +4. Redeploy in Dokploy + +> ⚠️ Always check the release notes for breaking changes before upgrading. + +--- + +## Production Checklist + +Before going live: + +- [ ] DNS configured: `pangolin.example.com` → server IP +- [ ] Firewall open: port 51820 (UDP) +- [ ] Admin password changed after first login +- [ ] MFA enabled on admin account +- [ ] TLS certificate active (check Dokploy Traefik for domain) +- [ ] SMTP configured (for user invites) +- [ ] Identity provider configured (optional but recommended) +- [ ] Volume backup strategy in place +- [ ] First tunnel tested end-to-end + +--- + +## Support & Resources + +- **Official Docs**: https://docs.pangolin.net/ +- **GitHub**: https://github.com/fosrl/pangolin +- **GitHub Issues**: https://github.com/fosrl/pangolin/issues +- **Gerbil (tunnel agent)**: https://github.com/fosrl/gerbil + +--- + +## Template Metadata + +- **Application**: Pangolin +- **Image**: `ghcr.io/fosrl/pangolin:sha256-3013a0e89e3259567fd86d23af50fc1c7ad9216ab0693ceb823b01c35e6acb5` +- **Gerbil**: `ghcr.io/fosrl/gerbil:1.3.0` +- **Type**: Identity-aware VPN and Proxy Server +- **Architecture**: Multi-service (Pangolin + Gerbil) +- **Storage**: SQLite in persistent volumes +- **Networking**: WireGuard VPN, admin UI via Dokploy Traefik +- **Status**: Production-Ready + +--- + +## License + +Pangolin is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) +See: https://github.com/fosrl/pangolin/blob/main/LICENSE diff --git a/blueprints/pangolin/docker-compose.yml b/blueprints/pangolin/docker-compose.yml new file mode 100644 index 0000000..d556819 --- /dev/null +++ b/blueprints/pangolin/docker-compose.yml @@ -0,0 +1,115 @@ +# ============================================================================= +# Pangolin - Identity-Aware VPN and Proxy Server +# https://github.com/fosrl/pangolin +# ============================================================================= +# Architecture: +# - Pangolin: Central control plane / admin dashboard (port 3001 API, 3000 UI) +# - Gerbil: WireGuard-based tunnel agent (UDP 51820) +# +# Admin dashboard is routed through Dokploy's Traefik (no separate Traefik +# instance in this stack). WireGuard UDP port is exposed directly on the host +# so remote tunnel clients can reach this server. +# ============================================================================= + +version: "3.8" + +services: + # =========================================================================== + # Pangolin - Identity-Aware Proxy Control Plane + # Admin dashboard on port 3000, REST API on port 3001 + # =========================================================================== + pangolin: + # NOTE: The tag "sha256-..." is a valid GHCR image tag (not a digest reference). + # GitHub Actions publishes images with this tag format alongside semantic version tags. + image: ghcr.io/fosrl/pangolin:sha256-3013a0e89e3259567fd86d23af50fc1c7ad9216ab0693ceb823b01c35e6acb5 + restart: unless-stopped + volumes: + # Shared config directory — WireGuard key (written by gerbil) is read here + # Pangolin's config.yml is injected via Dokploy config mounts + - pangolin-config:/app/config + networks: + - pangolin-internal + - dokploy-network + labels: + # =========================================================================== + # Traefik Routing - Pangolin Admin Dashboard + # Exposed via Dokploy's host Traefik on the configured domain + # =========================================================================== + - "traefik.enable=true" + - "traefik.http.routers.pangolin.rule=Host(`${PANGOLIN_DOMAIN}`)" + - "traefik.http.routers.pangolin.entrypoints=websecure" + - "traefik.http.routers.pangolin.tls.certresolver=letsencrypt" + - "traefik.http.services.pangolin.loadbalancer.server.port=3000" + - "traefik.docker.network=dokploy-network" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"] + interval: 10s + timeout: 10s + retries: 15 + start_period: 30s + + # =========================================================================== + # Gerbil - WireGuard Tunnel Agent + # Manages WireGuard VPN peers and writes the WireGuard key to the shared volume + # Requires NET_ADMIN and SYS_MODULE capabilities for WireGuard kernel module + # + # EXCEPTION TO BLUEPRINT "NO EXPOSED PORTS" RULE: + # WireGuard VPN (UDP 51820) must be directly reachable by remote tunnel + # clients — it cannot be routed through Dokploy's Traefik. This is the only + # port exposed on the host for this blueprint. + # =========================================================================== + gerbil: + image: ghcr.io/fosrl/gerbil:1.3.0 + 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: + # Gerbil shares the same config volume to write the WireGuard key + # Key is written to /var/config/key → readable by pangolin at /app/config/key + - pangolin-config:/var/config + cap_add: + - NET_ADMIN + - SYS_MODULE + ports: + # WireGuard VPN endpoint (UDP) — must be reachable by tunnel clients + - "${WIREGUARD_PORT:-51820}:51820/udp" + networks: + - pangolin-internal + healthcheck: + test: ["CMD-SHELL", "nc -z localhost 3004 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + +# ============================================================================= +# Volumes +# ============================================================================= +volumes: + # Shared config: both pangolin (/app/config) and gerbil (/var/config) mount + # this same volume so the WireGuard key generated by gerbil is readable by pangolin + pangolin-config: + driver: local + +# ============================================================================= +# Networks +# ============================================================================= +# EXCEPTION TO BLUEPRINT "DON'T DEFINE NETWORKS" RULE: +# This multi-service stack requires explicit network definitions because: +# - pangolin-internal: isolates Pangolin/Gerbil inter-service traffic from +# the public-facing Dokploy network (security isolation) +# - dokploy-network: required to attach the pangolin service to Dokploy's +# host Traefik so the admin dashboard can be routed and TLS-terminated +# Without these, service discovery between Pangolin and Gerbil breaks and the +# admin dashboard cannot be reached via Dokploy's Traefik. +# ============================================================================= +networks: + pangolin-internal: + driver: bridge + dokploy-network: + external: true diff --git a/blueprints/pangolin/logo.svg b/blueprints/pangolin/logo.svg new file mode 100644 index 0000000..f4546f5 --- /dev/null +++ b/blueprints/pangolin/logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PANGOLIN + diff --git a/blueprints/pangolin/template.toml b/blueprints/pangolin/template.toml new file mode 100644 index 0000000..10d1739 --- /dev/null +++ b/blueprints/pangolin/template.toml @@ -0,0 +1,151 @@ +# Pangolin - Identity-Aware VPN and Proxy Server +# Secure remote access with zero-trust identity enforcement +# https://github.com/fosrl/pangolin + +[variables] +# ============================================================================= +# Domain Configuration +# ============================================================================= +# Admin dashboard domain (e.g., pangolin.example.com) — REQUIRED +pangolin_domain = "${domain}" + +# Base domain for WireGuard tunnel clients and service routing (e.g., example.com) — REQUIRED +# This domain is used both as the WireGuard endpoint base and to build URLs for +# services accessed through WireGuard tunnels. +# Example: "example.com" +base_domain = "" + +# ============================================================================= +# Admin Account — REQUIRED +# ============================================================================= +# Initial admin email address (e.g., admin@example.com) +admin_email = "" +admin_password = "${password:32}" + +# ============================================================================= +# Security Secrets (auto-generated) +# ============================================================================= +app_secret = "${password:32}" +resource_access_secret = "${password:32}" + +# ============================================================================= +# Port Configuration +# ============================================================================= +# WireGuard VPN UDP port — exposed directly on the host +wireguard_port = "51820" + +# ============================================================================= +# Optional: SMTP Email Configuration +# Required for user invite emails, password resets, etc. +# ============================================================================= +smtp_host = "" +smtp_port = "587" +smtp_username = "" +smtp_password = "" +smtp_from_email = "" + +# ============================================================================= +# Application Settings +# ============================================================================= +log_level = "info" + +# ============================================================================= +# Domain Routing (Dokploy's Traefik) +# Points to Pangolin admin dashboard +# ============================================================================= +[[config.domains]] +serviceName = "pangolin" +port = 3000 +host = "${pangolin_domain}" + +# ============================================================================= +# Environment Variables +# ============================================================================= +[config.env] +PANGOLIN_DOMAIN = "${pangolin_domain}" +WIREGUARD_PORT = "${wireguard_port}" + +# ============================================================================= +# Pangolin Configuration File +# Mounted into the container at /app/config/config.yml +# ============================================================================= +[[config.mounts]] +serviceName = "pangolin" +mountPath = "/app/config/config.yml" +content = """ +# Pangolin Configuration +# Auto-generated by Dokploy — edit via environment variables or redeploy +# https://docs.pangolin.net/self-host/manual/install + +# ============================================================================= +# Application +# ============================================================================= +app: + dashboard_url: "https://${pangolin_domain}" + log_level: "${log_level}" + save_logs: false + secret: "${app_secret}" + +# ============================================================================= +# Domain +# ============================================================================= +domains: + base_domain: "${base_domain}" + +# ============================================================================= +# Admin User (initial setup — change password after first login) +# ============================================================================= +users: + server_admin: + email: "${admin_email}" + password: "${admin_password}" + +# ============================================================================= +# Ingress +# ============================================================================= +ingress: + base_domain: "${base_domain}" + +# ============================================================================= +# Gerbil (WireGuard tunnel agent) +# ============================================================================= +gerbil: + start_port: ${wireguard_port} + base_endpoint: "${base_domain}:${wireguard_port}" + block_size: 24 + site_block_size: 30 + subnet_group: "100.89.137.0/20" + +# ============================================================================= +# HTTP Server +# ============================================================================= +server: + # Port 443 is the standard HTTPS port used in Pangolin-generated resource URLs. + # The admin UI is routed through Dokploy's Traefik (no separate proxy in this stack). + external_port: 443 + session_cookie_name: "p_session_token" + resource_access_token_param: "p_token" + resource_access_token_headers: "X-Pangolin-Token" + resource_access_secret: "${resource_access_secret}" + cors: + origins: + - "https://${pangolin_domain}" + +# ============================================================================= +# Rate Limiting +# ============================================================================= +rate_limit: + window_minutes: 1 + max_requests: 100 + +# ============================================================================= +# Email / SMTP (optional — required for user invites and password resets) +# ============================================================================= +email: + smtp_host: "${smtp_host}" + smtp_port: ${smtp_port} + smtp_username: "${smtp_username}" + smtp_password: "${smtp_password}" + no_reply_address: "${smtp_from_email}" + email_header: "Pangolin" +"""