Deploying with Podman
This guide runs the panel's Docker image with rootless Podman on Fedora, RHEL, or Alma/Rocky Linux, using a Quadlet so systemd manages the container. Like the Docker guide, it uses SQLite and serves the panel over plain HTTP on port 80.
Prerequisites
- OS: Fedora, RHEL 9+, or Alma/Rocky Linux 9+ with SELinux enforcing.
- Packages:
podman5 or newer (sudo dnf install podman). - A regular (non-root) user to run the panel. The commands below use
your-user; replace it with that user's name.
Data is stored in Podman named volumes (pelican-data and pelican-logs), under ~/.local/share/containers/storage/volumes. Podman applies the correct SELinux labels to these automatically.
1. Allow Rootless Containers to Use Port 80
Unprivileged users can't bind ports below 1024 by default. Lower that limit to 80:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/podman-ports.conf
sudo sysctl --system
2. Create the Pod
Create the directories:
mkdir -p ~/pelican ~/.config/containers/systemd
Create the pod definition. Set APP_URL to the address users will visit.
apiVersion: v1
kind: Pod
metadata:
name: pelican
annotations:
# Optional: lets `podman auto-update` pull new panel images
io.containers.autoupdate: registry
spec:
securityContext:
sysctls:
# The panel's web server doesn't run as root, so let it listen on port 80 inside the pod
- name: net.ipv4.ip_unprivileged_port_start
value: "0"
containers:
- name: panel
image: ghcr.io/pelican/panel:latest
ports:
- containerPort: 80
hostPort: 80
volumeMounts:
- name: pelican-data
mountPath: /pelican-data
- name: pelican-logs
mountPath: /var/www/html/storage/logs
env:
- name: XDG_DATA_HOME
value: /pelican-data
- name: APP_URL
value: "http://YOUR_SERVER_IP"
volumes:
- name: pelican-data
persistentVolumeClaim:
claimName: pelican-data
- name: pelican-logs
persistentVolumeClaim:
claimName: pelican-logs
Then create the Quadlet, which tells systemd to run that pod:
[Unit]
Description=Pelican Panel
Wants=network-online.target
After=network-online.target
[Kube]
Yaml=%h/pelican/pelican.yaml
# Give the pod its own address so the panel can reach Wings and its own APP_URL on this host
Network=pasta:-a,10.0.2.15,-n,24,-g,10.0.2.2
[Install]
WantedBy=default.target
Without the Network= line, Podman gives the pod the host's IP address. The panel then can't reach anything on the host by that IP, such as Wings running on the same server.
3. Start the Panel
Let the panel keep running when you are logged out, then start it:
loginctl enable-linger $USER
systemctl --user daemon-reload
systemctl --user start pelican.service
Check that it is running and view its logs:
systemctl --user status pelican.service
podman logs -f pelican-panel
Back Up Your Encryption Key
The first time the container starts, it generates an APP_KEY, which is used as an encryption key. Save a copy in a secure place in case you need it later:
podman exec pelican-panel grep APP_KEY /pelican-data/.env
Installing
Open the installer in your browser at http://YOUR_SERVER_IP/installer to finish setting up the panel.
Optional Configuration
HTTPS and Reverse Proxies
The image supports the same BEHIND_PROXY, LE_EMAIL and TRUSTED_PROXIES environment variables as the Docker deployment. Add them under env: in pelican.yaml. If the panel serves HTTPS itself, also publish port 443 (containerPort: 443, hostPort: 443).
Upload Limit
The default file upload limit is 2MB. To raise it, copy the image's Caddyfile and edit it as shown in the Docker guide:
podman run --rm --entrypoint cat ghcr.io/pelican/panel:latest /etc/caddy/Caddyfile > ~/pelican/Caddyfile
Allow containers to read it under SELinux (semanage is in the policycoreutils-python-utils package):
sudo semanage fcontext -a -t container_file_t "/home/your-user/pelican/Caddyfile"
sudo restorecon -v ~/pelican/Caddyfile
Then mount it in pelican.yaml. Add this under the panel's volumeMounts:
- name: caddyfile
mountPath: /etc/caddy/Caddyfile
And add this under volumes (hostPath must be an absolute path):
- name: caddyfile
hostPath:
path: /home/your-user/pelican/Caddyfile
type: File
Restart the panel with systemctl --user restart pelican.service.
Automatic Updates
The io.containers.autoupdate annotation lets Podman update the panel image. Enable the timer to check daily:
systemctl --user enable --now podman-auto-update.timer
Managing Data
List the volumes, and find where their data is stored for backups:
podman volume ls
podman volume inspect pelican-data
podman volume rm pelican-data permanently deletes the panel's data, including the SQLite database and your encryption key.