Apache

Run FeatherPanel behind Apache 2 as a reverse proxy. The installer template, the modules it needs and corrections for WebSockets and headers.

On this page

When you pick the Apache access method, the installer runs a2enmod ssl proxy proxy_http proxy_wstunnel rewrite, renders the template into /etc/apache2/sites-available/featherpanel.conf and runs a2ensite featherpanel.

Template shipped with the panel

.github/docker/ssl/apache2.conf:

<VirtualHost *:80>
  ServerName your-domain.com
  Redirect permanent / https://your-domain.com/
</VirtualHost>

<VirtualHost *:443>
  ServerName your-domain.com

  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem

  ProxyPreserveHost On
  RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
  RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
  RequestHeader set X-Forwarded-Proto "https"
  RequestHeader set X-Forwarded-Port "443"
  ProxyPass / http://localhost:4831/
  ProxyPassReverse / http://localhost:4831/

  # WebSocket support
  ProxyPass /ws/ ws://localhost:4831/ws/
  ProxyPassReverse /ws/ ws://localhost:4831/ws/
</VirtualHost>

Things to check

The template has three gaps you should fix by hand:

  1. RequestHeader comes from mod_headers, which the installer does not enable. Run a2enmod headers, or Apache refuses to start with “Invalid command ‘RequestHeader’”.
  2. Apache matches ProxyPass rules in the order they appear, so ProxyPass / catches /ws/ before the WebSocket rule is reached. Use upgrade=websocket on the main rule (Apache 2.4.47 and later) instead of a separate /ws/ rule.
  3. Nothing raises the timeouts for long-lived connections. Add ProxyTimeout 3600.

A corrected virtual host:

<VirtualHost *:443>
  ServerName your-domain.com

  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem

  ProxyPreserveHost On
  ProxyTimeout 3600
  RequestHeader set X-Forwarded-Proto "https"
  RequestHeader set X-Forwarded-Port "443"
  ProxyPass / http://127.0.0.1:4831/ upgrade=websocket
  ProxyPassReverse / http://127.0.0.1:4831/
</VirtualHost>

mod_proxy adds X-Forwarded-For itself, so the corrected file does not set it.

sudo a2enmod ssl proxy proxy_http proxy_wstunnel headers rewrite
sudo a2ensite featherpanel
sudo apachectl configtest && sudo systemctl reload apache2

The plain HTTP template (.github/docker/plaintext/apache2.conf) is the same proxy block in a *:80 virtual host with X-Forwarded-Proto "http".