Skip to content

Pelican VM๐Ÿ”—

Debian 13 server
Basic SSH setup completed so I can access it through VS Code.

I used Pelican's official setup guide: Pelican Docs - Getting Started

Panel๐Ÿ”—

Getting Started๐Ÿ”—

PHP install command that is not listed in the guide (I'm installing PHP 8.4 because newer versions are not currently available in Debian):
apt install php8.4 php8.4-{gd,mysql,mbstring,bcmath,xml,curl,zip,intl,sqlite3,fpm}

Additional packages required:
apt install curl tar unzip

Webserver Configuration๐Ÿ”—

I use Caddy because it was easier for me to understand and modify.
The Caddy version in Debian is not new enough, so I had to add an additional repository.
I don't remember the exact commands since I used AI for it, but a newer version is required because older releases do not support the trusted_proxies option, which I need.
apt install caddy

Caddyfile

This is not exactly the same as the example in the Pelican documentation because I use NPM (Nginx Proxy Manager), meaning a "double proxy" setup together with Caddy.

{
    servers :80 {
        trusted_proxies static 192.168.1.22
        timeouts {
            read_body 120s
        }
    }
}

# Using :80 allows Caddy to listen on HTTP without interfering with NPM's SSL
pelican.timmo.ee:80 {
    root * /var/www/pelican/public

    # Crucial: This tells PHP that the original request was HTTPS
    # even though it's arriving at Caddy via HTTP
    php_fastcgi unix//run/php/php8.4-fpm.sock {
        env HTTPS on
        env HTTP_X_FORWARDED_PROTO https
        env HTTP_PROXY ""

        env PHP_VALUE "upload_max_filesize = 100M
        post_max_size = 100M"

        read_timeout 300s
        dial_timeout 300s
        write_timeout 300s
    }

    file_server

    # Keep your existing logic
    request_body {
        max_size 100m
    }
    respond /.ht* 403

    log {
        output file /var/log/caddy/pelican.log {
            roll_size 100MiB
            roll_keep_for 7d
        }
        level INFO
    }
}

Panel Setup๐Ÿ”—

After running the first command, you also need to modify the .env file.

.env file

There are two settings that definitely need to be configured:

APP_URL=https://pelican.timmo.ee
TRUSTED_PROXIES=192.168.1.22,192.168.1.26

For TRUSTED_PROXIES, I'm not actually sure whether the server itself needs to be included.
It was left there after troubleshooting.

Web Installer๐Ÿ”—

To access the website after modifying either the Caddyfile or the .env file, you may need to clear Laravel's cache.
If you do not do this, changes made to those files will not take effect.
All-in-one command:
php artisan optimize:clear

Individual commands:
php artisan config:clear
php artisan cache:clear
php artisan view:clear
php artisan route:clear

After modifying the Caddyfile, run:
systemctl restart caddy

Wings๐Ÿ”—

System Requirements

May not work inside Virtuozzo, OpenVZ (OVZ), or LXC.
Using a VM is recommended.

Installing Wings๐Ÿ”—

I followed the guide almost exactly as written in the wiki:
https://pelican.dev/docs/wings/install

Node / Server๐Ÿ”—

Honestly, I don't remember much here, but it was pretty straightforward.
Important: Don't forget to add the IP address and port used for server communication.
I don't remember whether this is configured under the Node or Server settings.

Old Information๐Ÿ”—

Old setup, didn't like it

Alpine LXC template was used.

I created a separate user called pelican and ran everything under that account because something broke when I tried creating a server in Pelican while running everything as root. It was related to Docker permissions, but I don't remember the exact issue.

Under the pelican user I also created a separate pelican directory and set it to 777 permissions so either the panel or Docker would stop complaining about permissions. I don't remember which one was causing the problem.

Panel + Wings Setup

I heavily used this guide:
https://blog.aflorzy.com/posts/setup-pelican-in-docker

Ignore the NPM section.
The guide is outdated because it does not use the "HTTPS with (reverse) proxy" option when creating a Node. That option does not appear in the screenshots.

Compose file
services:
  panel:
    image: ghcr.io/pelican-dev/panel:latest
    container_name: pelican-panel
    restart: always
    stdin_open: true
    tty: true
    ports:
      - "8080:80"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ./panel/data:/pelican-data
      - ./panel/logs:/var/www/html/storage/logs
      - ./panel/Caddyfile:/etc/caddy/Caddyfile
    environment:
      TZ: Europe/Tallinn
      APP_TIMEZONE: Europe/Tallinn
      APP_ENV: production
      APP_URL: "https://pelican.timmo.ee"
      ADMIN_EMAIL: "pelican.admin@timmo.ee"
      TRUSTED_PROXIES: 192.168.1.22
    networks:
      - pelican

  wings:
    image: ghcr.io/pelican-dev/wings:latest
    container_name: pelican-wings
    restart: unless-stopped
    ports:
      - "2022:2022"
      - "8443:443"
    stdin_open: true
    tty: true
    environment:
      TZ: Europe/Tallinn
      APP_TIMEZONE: Europe/Tallinn
      WINGS_UID: 1000
      WINGS_GID: 1000
      WINGS_USERNAME: pelican
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "/var/lib/docker/containers/:/var/lib/docker/containers/"
      - "/etc/pelican/:/etc/pelican/"
      - "/var/lib/pelican/:/var/lib/pelican/"
      - "/var/log/pelican/:/var/log/pelican/"
      - "/tmp/pelican/:/tmp/pelican/"
      - "/etc/ssl/certs:/etc/ssl/certs:ro"
    networks:
      - wings1

networks:
  pelican:
    name: pelican
  wings1:
    name: wings1
    driver: bridge
    ipam:
      config:
        - subnet: 172.50.0.0/16
    driver_opts:
      com.docker.network.bridge.name: wings1

Do not start Wings immediately. It requires additional configuration that is partially generated by the Panel.
A Caddyfile was also required to allow access through NPM or another reverse proxy.

Caddyfile contents
{
    admin off

    servers {
        trusted_proxies static 192.168.1.22
    }
}

# Only listen on HTTP internally because NPM handles TLS externally.
:80 {
    root * /var/www/html/public
    encode gzip

    php_fastcgi 127.0.0.1:9000 {
        env PHP_VALUE "upload_max_filesize = 256M
                      post_max_size = 256M"
    }

    file_server
}

Directory structure looked roughly like this:

> pelican
    > docker-compose.yml
    > panel
        > Caddyfile

The remaining directories should be created automatically, although I don't remember whether I had to manually fix permissions.

Creating a Node (Wings)

During the Node creation process you are given a basic configuration file, but that alone is not enough.
This is probably because Wings has not been fully migrated to Docker yet and the developers are still working on it.
The guide recommends adding a separate Docker network section, and without it the setup would not work anyway.

Add the network section
docker:
  network:
    interface: 172.50.0.1
    dns:
      - 192.168.1.1 # Replace with your default gateway if different
      - 1.0.0.1
    name: wings1
    ispn: false
    driver: bridge
    network_mode: wings1
    is_internal: false
    enable_icc: true
    network_mtu: 1500
    interfaces:
      v4:
        subnet: 172.50.0.0/16
        gateway: 172.50.0.1
      v6:
        subnet: fdba:17c8:6c94::/64
        gateway: fdba:17c8:6c94::1011
allowed_mounts: []
allowed_origins: []
allow_cors_private_network: false
ignore_panel_config_updates: false

Access

External access is primarily provided through a Cloudflared tunnel.
I had to add an entry to the Cloudflared configuration so that mc.timmo.ee would forward to tcp://ip:port.
As a backup I also use PlayitGG.
Cloudflare performs noticeably better, with approximately 2โ€“3x lower latency.