Guide to deploy Pangolin on Flatcar OS 2025








Guide to Deploy Pangolin on Flatcar OS

As a prerequisite to deployment, confirm the following: (1) all required network ports are open and accessible (TCP 80, TCP 443, UDP 51820); and (2) the DNS records for your domain correctly resolve to the public IP address of your Flatcar VPS.

1. Initial Server Setup

First, SSH into your Flatcar OS server:

ssh core@your-server-ip

Create a persistent directory for Pangolin data since Flatcar OS uses an immutable filesystem:

sudo mkdir -p /opt/pangolin
sudo chown core:core /opt/pangolin
cd /opt/pangolin

2. Set Up Docker Compose

Create a Docker Compose wrapper script that ensures compatibility with Flatcar OS:

sudo mkdir -p /opt/bin
sudo tee /opt/bin/docker-compose << 'EOF'
#!/bin/bash
docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v "$PWD:$PWD" \
    -w="$PWD" \
    docker/compose:1.29.2 "$@"
EOF

sudo chmod +x /opt/bin/docker-compose

3. Download the Pangolin Installer

Download the Pangolin installer:

wget -O installer "https://github.com/fosrl/pangolin/releases/download/1.0.0-beta.14/installer_linux_amd64"
chmod +x ./installer

4. Run the Installer

Run the installer with sudo:

sudo ./installer

When prompted, provide the following information:

  • Your base domain name (e.g., example.com)
  • Dashboard domain name (e.g., proxy.example.com)
  • Let’s Encrypt email address
  • Choose whether to install Gerbil for tunneling
  • Set up admin user credentials
  • Configure security settings
  • Set up email configuration (optional)

5. Create a Systemd Service

Create a systemd service file to manage Pangolin:

sudo mkdir -p /etc/systemd/system
sudo tee /etc/systemd/system/pangolin.service << 'EOF'
[Unit]
Description=Pangolin Service
After=docker.service
Requires=docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/opt/pangolin
ExecStartPre=/bin/sleep 5
ExecStart=/opt/bin/docker-compose up
ExecStop=/opt/bin/docker-compose down
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

6. Start Pangolin Service

Enable and start the Pangolin service:

sudo systemctl daemon-reload
sudo systemctl enable pangolin
sudo systemctl start pangolin

7. Verify Installation

Check if all containers are running:

cd /opt/pangolin
/opt/bin/docker-compose ps

You should see containers for:

  • Pangolin
  • Traefik
  • Gerbil (if you chose to install it)

8. Monitor Logs

You can monitor the logs using:

cd /opt/pangolin
/opt/bin/docker-compose logs -f

9. Access the Dashboard

Once everything is running, access your Pangolin dashboard at the domain you configured (e.g., https://proxy.example.com).

Troubleshooting Tips

If you encounter any issues:

  1. Check the container logs:

    cd /opt/pangolin
    /opt/bin/docker-compose logs
    
  2. Verify all ports are accessible:

    sudo ss -tulpn
    
  3. Check systemd service status:

    sudo systemctl status pangolin
    
  4. If the service fails to start, try starting Docker Compose manually:

    cd /opt/pangolin
    /opt/bin/docker-compose up -d
    
  5. Ensure all configuration files exist:

    ls -la /opt/pangolin/config/
    

Remember that Flatcar OS uses an immutable file system, so all persistent data should be stored in the /opt directory.

Why did you decide to use v1 compose?

on flatcar, the containerized V1 approach is simpler for one-off deployments and systemd integration.

my current deployment

my butane Config with all features:

  • my SSH public key (replace the placeholder)
  • automatic firewall rules (iptables) for required ports: 22 (SSH), 80, 443, 51820/UDP
  • restart service for updates (a simple watchdog/restart service + update strategy)

prod— pangolin.bu (Complete Butane Config)

variant: flatcar
version: 1.0.0

passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... YOUR_PUBLIC_KEY_HERE ..."   # ← Replace with your actual public key

storage:
  directories:
    - path: /opt/pangolin
      mode: 0755
      user:
        id: 500
      group:
        id: 500

  files:
    # Docker Compose V2 (latest)
    - path: /opt/bin/docker-compose
      mode: 0755
      overwrite: true
      contents:
        source: "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64"

    # Symlink for convenience
    - path: /usr/local/bin/docker-compose
      mode: 0755
      overwrite: true
      contents:
        inline: |
          #!/bin/sh
          exec /opt/bin/docker-compose "$@"

systemd:
  units:
    # Setup directories and permissions
    - name: pangolin-setup.service
      enabled: true
      contents: |
        [Unit]
        Description=Prepare Pangolin environment
        After=network-online.target
        Before=pangolin.service

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        User=root
        ExecStart=/usr/bin/mkdir -p /opt/pangolin/config
        ExecStart=/usr/bin/chown -R core:core /opt/pangolin
        ExecStart=/usr/bin/chmod -R 755 /opt/bin

        [Install]
        WantedBy=multi-user.target

    # Firewall rules (iptables)
    - name: pangolin-firewall.service
      enabled: true
      contents: |
        [Unit]
        Description=Pangolin Firewall Rules
        After=network-online.target
        Before=pangolin.service

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=/usr/sbin/iptables -P INPUT DROP
        ExecStart=/usr/sbin/iptables -A INPUT -i lo -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -p tcp --dport 22 -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -p tcp --dport 80 -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -p tcp --dport 443 -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -p udp --dport 51820 -j ACCEPT
        ExecStart=/usr/sbin/iptables -A INPUT -j DROP
        ExecStart=/usr/sbin/iptables-save > /var/lib/iptables/rules-save
        ExecStop=/usr/sbin/iptables-restore < /var/lib/iptables/rules-save

        [Install]
        WantedBy=multi-user.target

    # Pangolin restart service (for updates/maintenance)
    - name: pangolin-restart.service
      enabled: true
      contents: |
        [Unit]
        Description=Restart Pangolin after updates or config changes
        After=pangolin.service
        Wants=pangolin.service

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        User=root
        WorkingDirectory=/opt/pangolin
        ExecStart=/opt/bin/docker-compose down
        ExecStart=/opt/bin/docker-compose pull
        ExecStart=/opt/bin/docker-compose up -d
        TimeoutStartSec=120

    # Pangolin main service
    - name: pangolin.service
      enabled: true
      contents: |
        [Unit]
        Description=Pangolin Service
        After=docker.service network-online.target pangolin-setup.service pangolin-firewall.service
        Requires=docker.service

        [Service]
        Type=simple
        User=root
        WorkingDirectory=/opt/pangolin
        ExecStartPre=/bin/sleep 5
        ExecStart=/opt/bin/docker-compose up -d
        ExecStop=/opt/bin/docker-compose down
        Restart=on-failure
        RestartSec=10

        [Install]
        WantedBy=multi-user.target

How to Use

  1. Replace the SSH key in the Butane file with your actual public key (cat ~/.ssh/id_ed25519.pub or similar).

  2. Convert to Ignition (on your local machine):

docker run --rm -i quay.io/coreos/butane:release --pretty < pangolin.bu > ignition.json
  1. Provision your Flatcar instance with ignition.json.

  2. After first boot, run the interactive installer once:

ssh core@your-server-ip
cd /opt/pangolin
wget -O installer "https://github.com/fosrl/pangolin/releases/download/1.19.2/installer_linux_amd64"
chmod +x ./installer
sudo ./installer

The service will start automatically after that.

Notes

  • Firewall: Strict default-deny policy. Only opens the necessary ports. You can adjust it later if needed.
  • Restart service: Runs docker-compose pull && up -d — useful after you update Pangolin containers or configs.
  • SSH: Only your key is authorized (password login disabled by default on Flatcar).