# Apache

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

Source: https://featherpanel.com/docs/panel/web-server/apache/

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`:

```apache
<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:

```apache
<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.

```bash
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"`.
