In today’s connected world, self-hosting applications presents a significant challenge: how do you make services available online without compromising your entire home network? Traditional solutions like port forwarding or VPNs often create security vulnerabilities or management headaches.
This two-part guide explores implementing a modern, secure architecture using Pangolin and Newt that keeps your network safe while making selected applications accessible.
Understanding the Challenge
When self-hosting applications that need internet accessibility, several problems emerge:
- Security perimeter expansion: Traditional port forwarding exposes your network’s edge directly to the internet
- Authentication complexity: Managing access control across multiple applications
- Network isolation difficulties: Preventing compromised services from affecting other systems
- Dynamic IP complications: Maintaining connections when home IP addresses change
- SSL certificate management: Securing connections properly at scale
The solution combines several technologies - hosting Pangolin on a VPS (Virtual Private Server) while running applications locally with careful network isolation.
Architecture Overview: The Separated Concerns Approach
Our architecture creates three distinct security domains:
- Internet-facing VPS: Hosts only Pangolin stack components
- Exposed applications network: Contains only services intended for external access
- Private home network: Remains completely isolated from internet exposure
This separation follows the principle of least privilege - only the minimal necessary components receive internet exposure.
Key Components
1. Cloud VPS
- Hosts the Pangolin stack, functioning as the secure gateway
- Exposes only necessary ports (80, 443, 51820)
- Contains no actual application data or sensitive information
- Functions as a “reverse bastion” for secure tunneling
2. Pangolin Stack (on VPS)
- Pangolin Server: Management interface and authentication system
- Gerbil: WireGuard tunnel manager
- Traefik: Reverse proxy with SSL termination
- CrowdSec: Security protection layer
3. Newt Client (on isolated local network)
- Runs in a confined environment (dedicated VLAN or container network)
- Only connects to approved application containers
- Maintains encrypted tunnel to VPS
- Limited network visibility
4. Application containers
- Run on isolated network segment
- Only communicate with Newt and necessary dependencies
- Unaware of direct internet exposure
Detailed Network Isolation Implementation
graph TD
subgraph Internet["INTERNET"]
VPS["CLOUD VPS<br/>PANGOLIN STACK"]
end
subgraph HomeNetwork["HOME NETWORK (192.168.1.0/24)"]
Router["HOME ROUTER/FIREWALL"]
subgraph VLAN10["MANAGEMENT VLAN (192.168.10.0/24)"]
Proxmox["PROXMOX<br/>TYPE 1 HYPERVISOR"]
Admin["Admin Workstation"]
end
subgraph RIG["PHYSICAL SERVER<br/>i5 12600K, 64GB DDR4, NVME 250GB, 2x4TB HDD"]
Proxmox
end
subgraph VLAN20["EXPOSED APPS VLAN (192.168.20.0/24)<br/>LIMITED NETWORK VISIBILITY"]
ExposedVM["UBUNTU VM<br/>ISOLATED NETWORK"]
subgraph ExposedContainers["DOCKER NETWORK: exposed-apps (172.20.0.0/16)"]
Newt["NEWT CLIENT<br/>(WireGuard Tunnel)"]
NextcloudContainer["Nextcloud<br/>172.20.0.10"]
JellyfinContainer["Jellyfin<br/>172.20.0.11"]
HomeAssistantContainer["Home Assistant<br/>172.20.0.12"]
DashboardContainer["Homarr Dashboard<br/>172.20.0.13"]
OtherExposedApps["Other Exposed<br/>Applications"]
end
end
subgraph VLAN30["PRIVATE APPS VLAN (192.168.30.0/24)<br/>NO INTERNET EXPOSURE"]
PrivateVM["UBUNTU VM<br/>INTERNAL ONLY"]
subgraph PrivateContainers["DOCKER NETWORK: private-apps (172.30.0.0/16)"]
AdGuardHome["AdGuard Home"]
SecurityTools["Security Tools<br/>CrowdSec, Fail2Ban,<br/>WatchYourLAN"]
PrivateServices["Private Services<br/>Database, Storage, etc."]
end
end
subgraph VLAN40["PENTESTING VLAN (192.168.40.0/24)<br/>ISOLATED + MONITORED"]
KaliVM["KALI LINUX VM<br/>CTF/PENTESTING<br/>USUALLY OFFLINE"]
end
end
subgraph VPS_COMPONENTS["PANGOLIN STACK ON VPS"]
PANGOLIN["PANGOLIN SERVER<br/>(Management interface)"]
GERBIL["GERBIL<br/>(WireGuard tunnels manager)"]
TRAEFIK["TRAEFIK<br/>(Reverse proxy with SSL)"]
CROWDSEC_VPS["CROWDSEC<br/>(Security layer)"]
end
Router --> VLAN10
Router --> VLAN20
Router --> VLAN30
Router --> VLAN40
VPS --> VPS_COMPONENTS
VPS <-->|Encrypted WireGuard Tunnel<br/>No port forwarding needed| Newt
Newt <-->|Proxies requests to| ExposedContainers
ENDUSER["END USERS"] -->|HTTPS Requests| VPS
classDef exposed fill:#f9d5e5,stroke:#333,stroke-width:1px;
classDef private fill:#eeeeee,stroke:#333,stroke-width:1px;
classDef infrastructure fill:#d5e8f9,stroke:#333,stroke-width:1px;
classDef vps fill:#d9f,stroke:#333,stroke-width:2px;
classDef internet fill:#f5f5f5,stroke:#666,stroke-width:1px;
class VLAN20,ExposedVM,ExposedContainers,Newt,NextcloudContainer,JellyfinContainer,HomeAssistantContainer,DashboardContainer,OtherExposedApps exposed;
class VLAN30,PrivateVM,PrivateContainers,AdGuardHome,SecurityTools,PrivateServices private;
class RIG,Proxmox,VLAN10,Admin,Router,VLAN40,KaliVM infrastructure;
class VPS,VPS_COMPONENTS,PANGOLIN,GERBIL,TRAEFIK,CROWDSEC_VPS vps;
class Internet,ENDUSER internet;
Network Segmentation Explained
The key to this setup is proper network segmentation using VLANs (Virtual Local Area Networks) or similar isolation techniques:
-
Management VLAN (192.168.10.0/24)
- Contains hypervisor management interface
- Admin access only
- Strict firewall rules
-
Exposed Apps VLAN (192.168.20.0/24)
- Contains only the VM running Newt and exposed applications
- Cannot access other network segments
- Docker containers further isolate applications (172.20.0.0/16)
- Newt only has permissions to access specific containers
-
Private Apps VLAN (192.168.30.0/24)
- Contains sensitive services never exposed to internet
- No route to Newt or exposed applications
- Complete isolation from internet-facing components
-
Pentesting VLAN (192.168.40.0/24)
- Isolated environment for security testing
- Heavily monitored
- Usually powered off when not in use
Firewall Rules Implementation
The firewall configuration creates strict boundaries between network segments:
-
From Management VLAN:
- Allow established connections
- Allow SSH to Exposed and Private VLANs
- Allow Proxmox management to all VMs
- Deny all other traffic
-
From Exposed Apps VLAN:
- Allow established connections
- Allow DNS to specific servers
- Block all access to Management VLAN
- Block all access to Private VLAN
- Allow outbound internet (WireGuard tunnel only)
-
From Private Apps VLAN:
- Allow established connections
- Allow DNS and DHCP
- Block all access to Exposed VLAN
- Allow controlled access to Management VLAN (monitoring)
- Block direct internet access
Setting Up the VPS Pangolin Stack
The VPS component serves as our secure gateway to the internet. Here’s how to set it up:
1. VPS Requirements
- Ubuntu 24.04 LTS or similar
- Minimum 2 vCPU, 4GB RAM
- 40GB SSD storage
- Unmetered or generous bandwidth allocation
- Public IPv4 address
- Provider with good uptime (Linode, DigitalOcean, Vultr, etc.)
2. Initial Server Hardening
# Update system
sudo apt update && apt upgrade -y
# Install basic security tools
sudo apt install -y ufw fail2ban unattended-upgrades
# Configure firewall
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 51820/udp
ufw enable
# Configure automatic updates
sudo dpkg-reconfigure --priority=low unattended-upgrades
3. Installing Docker and Docker Compose
# Install requirements
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# Install Docker and docker compose (only for ubuntu)
wget https://gist.githubusercontent.com/hhftechnology/64c9ee84795b01bfac73de24a702db7c/raw/fbe6c596284e405e7c9be613b489ad53d24a4467/install-docker.sh
chmod +x install-docker.sh
sudo ./install-docker.sh
# Create Docker network
docker network create pangolin
4. Pangolin Stack Deployment (you have 2 options manual via compose with crowdsec or auto install)
Manual
Create a project directory and set up the Docker Compose configuration:
mkdir -p /opt/pangolin
cd /opt/pangolin
Create a docker-compose.yml file with the following content:
networks:
pangolin:
external: true
services:
pangolin:
image: fosrl/pangolin:1.0.0-beta.14 #use whatever latest version avaliable but dont use latest tag
container_name: pangolin
restart: unless-stopped
networks:
- pangolin
volumes:
- ./config:/app/config
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
interval: "3s"
timeout: "3s"
retries: 5
gerbil:
image: fosrl/gerbil:latest
container_name: gerbil
restart: unless-stopped
depends_on:
pangolin:
condition: service_healthy
networks:
- pangolin
extra_hosts:
- "pangolin:172.19.0.2" #read crowdsec guide why ip is used.
command:
- --reachableAt=http://gerbil:3003
- --generateAndSaveKeyTo=/var/config/key
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
- --reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth
volumes:
- ./config/:/var/config
cap_add:
- NET_ADMIN
- SYS_MODULE
ports:
- 51820:51820/udp
- 443:443
- 80:80
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
environment:
GID: "${GID-1000}"
COLLECTIONS: crowdsecurity/traefik
networks:
- pangolin
volumes:
- ./config/crowdsec:/etc/crowdsec
- ./config/crowdsec/db:/var/lib/crowdsec/data
- ./config/traefik/logs:/var/log/traefik
restart: unless-stopped
traefik:
image: traefik:v3.3.3
container_name: traefik
restart: unless-stopped
network_mode: service:gerbil
depends_on:
pangolin:
condition: service_healthy
command:
- --configFile=/etc/traefik/traefik_config.yml
volumes:
- ./config/traefik:/etc/traefik:ro
- ./config/letsencrypt:/letsencrypt
- ./config/traefik/logs:/var/log/traefik
Create the initial configuration directories:
mkdir -p config/traefik config/letsencrypt config/crowdsec
Auto Install
1. Downloading and Running the Installer
Installer binaries for Linux can be found in the Github releases for ARM and AMD64 (x86_64).
For example, on amd64 download the installer with either wget or curl and make it executable:
wget -O installer "https://github.com/fosrl/pangolin/releases/download/1.0.0-beta.14/installer_linux_amd64" && chmod +x ./installer
The downloaded files will be named installer in the current directory.
The installer must be run as root. If you’re not already root, switch to the root user or use sudo:
sudo ./installer
The installer will place all files in the current directory. If you want to install Pangolin in a different directory, you can move the installer to that directory and run it there.
2. Basic Configuration
The installer will prompt you for the following basic information:
- Base Domain Name: Enter your base fully qualified domain name (without any subdomains) Example:
example.com - Dashboard Domain Name: The domain where the application will be hosted. This is used for many things, including generating links. You can run Pangolin on a subdomain or root domain. Example:
proxy.example.com - Let’s Encrypt Email: Provide an email address for SSL certificate registration with Lets Encrypt. This should be an email you have access to.
- Tunneling You can choose not to install Gerbil for tunneling support - in this config it will just be a normal reverse proxy. See how to use without tunneling.
3. Admin User Setup
You’ll need to configure the admin user. This is the first user in the system. You will log in initially with this user.
- Admin Email: Defaults to
admin@yourdomain.combut can be customized - Admin Password: Must meet these requirements:
- At least 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one digit
- At least one special character
4. Security Settings
Configure security options:
- Signup Without Invite: Choose whether to disable user registration without invites (defaults to disabled). This removes the “Sign Up” button on the login form and is recommended for private deployments.
- Organization Creation: Decide if users can create their own organizations (defaults to enabled)
5. Email Configuration
Decide whether to enable email functionality. This allows Pangolin to send transactional emails like OTP or email verification requests.
If enabled, you’ll need to provide:
- SMTP host
- SMTP port (defaults to 587)
- SMTP username
- SMTP password
- No-reply email address. This is the sender email address that Pangolin will email from. Many times this should be the same as the username.
6. Docker Installation
If Docker isn’t already installed, the installer will:
- Detect your Linux distribution
- Offer to install Docker automatically
- Install the appropriate version for your distribution
7. Container Deployment
After configuration, the installer will:
- Pull the necessary Docker containers
- Create required directories:
config/config/letsencrypt/config/db/config/logs/
- Generate configuration files
- Start the containers using Docker Compose
Post-Installation
After successful installation:
- The system will be accessible at your configured domain
- You can log in using the admin email and password you provided
5. Configuring Pangolin (skip this if you have used auto installer)
After starting the containers for the first time, Pangolin will generate a default configuration. We’ll need to modify it to match our requirements:
# Start the stack to generate initial config
docker compose up -d
sleep 10
docker compose down
# Now edit the configuration
nano config/config.yml
Edit the configuration file with appropriate values:
app:
dashboard_url: "https://pangolin.yourdomain.com"
base_domain: "yourdomain.com"
log_level: "info"
save_logs: true
server:
external_port: 3000
internal_port: 3001
next_port: 3002
internal_hostname: "pangolin"
session_cookie_name: "pangolin_session"
resource_access_token_param: "p_token"
resource_session_request_param: "p_session_request"
trust_proxy: true
dashboard_session_length_hours: 168
resource_session_length_hours: 720
traefik:
cert_resolver: "letsencrypt"
http_entrypoint: "web"
https_entrypoint: "websecure"
prefer_wildcard_cert: true
additional_middlewares: ["crowdsec-bouncer@file"]
gerbil:
start_port: 51820
base_endpoint: "yourdomain.com"
use_subdomain: false
subnet_group: 100.80.0.0/20
block_size: 24
site_block_size: 30
rate_limits:
global:
window_minutes: 1
max_requests: 100
users:
server_admin:
email: "admin@yourdomain.com"
password: "YourSecureAdminPassword123!"
flags:
require_email_verification: false
disable_signup_without_invite: true
disable_user_create_org: true
allow_raw_resources: true
allow_base_domain_resources: false
6. Starting the Pangolin Stack
Start the stack and verify all components are running:
docker compose up -d
docker compose ps
You should now be able to access the Pangolin dashboard at your configured domain. Log in with the admin credentials you specified in the config file.
Next Steps in Part 2
In the next part, we’ll cover:
- Setting up the isolated network for exposed applications
- Configuring Newt in a confined environment
- Connecting exposed applications securely
- Implementing proper monitoring and logging
- Testing the security boundaries
By properly segmenting your network and using this architecture, you’ll gain the ability to expose selected applications to the internet without compromising your entire home network’s security.