2020-02-29 00:43:59 +00:00
---
layout: default
title: HAProxy
2020-04-28 09:17:45 +00:00
parent: Proxy Integration
2020-02-29 00:43:59 +00:00
grand_parent: Deployment
nav_order: 1
---
# HAProxy
[HAProxy] is a reverse proxy supported by **Authelia** .
2020-04-28 09:17:45 +00:00
## Requirements
2020-02-29 00:43:59 +00:00
2020-04-28 09:17:45 +00:00
You need the following to run Authelia with HAProxy:
2020-09-10 00:52:57 +00:00
* HAProxy 1.8.4+ (2.2.0+ recommended)
2020-04-28 09:17:45 +00:00
* `USE_LUA=1` set at compile time
2020-09-10 00:52:57 +00:00
* [haproxy-lua-http ](https://github.com/haproxytech/haproxy-lua-http ) must be available within the Lua path
* A `json` library within the Lua path (dependency of haproxy-lua-http, usually found as OS package `lua-json` )
* With HAProxy 2.1.3+ you can use the [`lua-prepend-path`] configuration option to specify the search path.
* [haproxy-auth-request ](https://github.com/TimWolla/haproxy-auth-request/blob/master/auth-request.lua )
2020-04-28 09:17:45 +00:00
## Configuration
Below you will find commented examples of the following configuration:
* Authelia portal
* Protected endpoint (Nextcloud)
2021-02-23 23:35:04 +00:00
* Protected endpoint with `Authorization` header for basic authentication (Heimdall)
2020-04-28 09:17:45 +00:00
* [haproxy-auth-request ](https://github.com/TimWolla/haproxy-auth-request/blob/master/auth-request.lua )
With this configuration you can protect your virtual hosts with Authelia, by following the steps below:
2021-02-23 23:35:04 +00:00
1. Add host(s) to the `protected-frontends` or `protected-frontends-basic` ACLs to support protection with Authelia.
2020-04-28 09:17:45 +00:00
You can separate each subdomain with a `|` in the regex, for example:
2020-04-28 10:53:06 +00:00
```
2020-11-24 01:35:38 +00:00
acl protected-frontends hdr(host) -m reg -i ^(?i)(jenkins|nextcloud|phpmyadmin)\.example\.com
2021-02-23 23:35:04 +00:00
acl protected-frontends-basic hdr(host) -m reg -i ^(?i)(heimdall)\.example\.com
2020-04-28 09:17:45 +00:00
```
2. Add host ACL(s) in the form of `host-service` , this will be utilised to route to the correct
backend upon successful authentication, for example:
2020-04-28 10:53:06 +00:00
```
2020-04-28 09:17:45 +00:00
acl host-jenkins hdr(host) -i jenkins.example.com
2020-05-14 03:26:52 +00:00
acl host-nextcloud hdr(host) -i nextcloud.example.com
2020-04-28 09:17:45 +00:00
acl host-phpmyadmin hdr(host) -i phpmyadmin.example.com
2021-02-23 23:35:04 +00:00
acl host-heimdall hdr(host) -i heimdall.example.com
2020-04-28 09:17:45 +00:00
```
3. Add backend route for your service(s), for example:
2020-04-28 10:53:06 +00:00
```
2020-04-28 09:17:45 +00:00
use_backend be_jenkins if host-jenkins
use_backend be_nextcloud if host-nextcloud
use_backend be_phpmyadmin if host-phpmyadmin
2021-02-23 23:35:04 +00:00
use_backend be_heimdall if host-heimdall
2020-04-28 09:17:45 +00:00
```
4. Add backend definitions for your service(s), for example:
2020-04-28 10:53:06 +00:00
```
2020-04-28 09:17:45 +00:00
backend be_jenkins
server jenkins jenkins:8080
backend be_nextcloud
server nextcloud nextcloud:443 ssl verify none
backend be_phpmyadmin
server phpmyadmin phpmyadmin:80
2021-02-23 23:35:04 +00:00
backend be_heimdall
server heimdall heimdall:443 ssl verify none
2020-04-28 09:17:45 +00:00
```
### Secure Authelia with TLS
There is a [known limitation ](https://github.com/TimWolla/haproxy-auth-request/issues/12 ) with haproxy-auth-request with regard to TLS-enabled backends.
If you want to run Authelia TLS enabled the recommended workaround utilises HAProxy itself to proxy the requests.
2020-09-23 07:29:46 +00:00
This comes at a cost of two additional TCP connections, but allows the full HAProxy configuration flexibility with regard
2020-04-28 09:17:45 +00:00
to TLS verification as well as header rewriting. An example of this configuration is also be provided below.
#### Configuration
##### haproxy.cfg
2020-04-28 10:53:06 +00:00
```
2020-04-28 09:17:45 +00:00
global
2020-09-10 00:52:57 +00:00
# Path to haproxy-lua-http, below example assumes /usr/local/etc/haproxy/haproxy-lua-http/http.lua
lua-prepend-path /usr/local/etc/haproxy/?/http.lua
2020-04-28 09:17:45 +00:00
# Path to haproxy-auth-request
lua-load /usr/local/etc/haproxy/auth-request.lua
log stdout format raw local0 debug
defaults
mode http
log global
option httplog
option forwardfor
frontend fe_http
bind *:443 ssl crt /usr/local/etc/haproxy/haproxy.pem
# Host ACLs
2020-11-24 01:35:38 +00:00
acl protected-frontends hdr(host) -m reg -i ^(?i)(nextcloud)\.example\.com
2021-02-23 23:35:04 +00:00
acl protected-frontends-basic hdr(host) -m reg -i ^(?i)(heimdall)\.example\.com
2020-04-28 09:17:45 +00:00
acl host-authelia hdr(host) -i auth.example.com
acl host-nextcloud hdr(host) -i nextcloud.example.com
2021-02-23 23:35:04 +00:00
acl host-heimdall hdr(host) -i heimdall.example.com
2020-04-28 09:17:45 +00:00
2021-03-18 08:56:08 +00:00
# This is required if utilising basic auth with /api/verify?auth=basic
http-request set-var(txn.host) hdr(Host)
2020-04-28 09:17:45 +00:00
http-request set-var(req.scheme) str(https) if { ssl_fc }
http-request set-var(req.scheme) str(http) if !{ ssl_fc }
http-request set-var(req.questionmark) str(?) if { query -m found }
2021-03-05 04:18:31 +00:00
# These are optional if you wish to use the Methods rule in the access_control section.
#http -request set-var(req.method) str(CONNECT) if { method CONNECT }
#http -request set-var(req.method) str(GET) if { method GET }
#http -request set-var(req.method) str(HEAD) if { method HEAD }
#http -request set-var(req.method) str(OPTIONS) if { method OPTIONS }
#http -request set-var(req.method) str(POST) if { method POST }
#http -request set-var(req.method) str(TRACE) if { method TRACE }
#http -request set-var(req.method) str(PUT) if { method PUT }
#http -request set-var(req.method) str(PATCH) if { method PATCH }
#http -request set-var(req.method) str(DELETE) if { method DELETE }
#http -request set-header X-Forwarded-Method %[var(req.method)]
2020-09-22 23:06:26 +00:00
# Required headers
2020-04-28 09:17:45 +00:00
http-request set-header X-Real-IP %[src]
2021-03-05 04:18:31 +00:00
http-request set-header X-Forwarded-Method %[var(req.method)]
2020-04-28 09:17:45 +00:00
http-request set-header X-Forwarded-Proto %[var(req.scheme)]
http-request set-header X-Forwarded-Host %[req.hdr(Host)]
http-request set-header X-Forwarded-Uri %[path]%[var(req.questionmark)]%[query]
# Protect endpoints with haproxy-auth-request and Authelia
http-request lua.auth-request be_authelia /api/verify if protected-frontends
2021-02-23 23:35:04 +00:00
# Force `Authorization` header via query arg to /api/verify
http-request lua.auth-request be_authelia /api/verify?auth=basic if protected-frontends-basic
2021-03-18 08:56:08 +00:00
# Redirect protected-frontends to Authelia if not authenticated
http-request redirect location https://auth.example.com/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query] if protected-frontends !{ var(txn.auth_response_successful) -m bool }
# Send 401 and pass `WWW-Authenticate` header on protected-frontend-basic if not pre-authenticated
http-request set-var(txn.auth) var(req.auth_response_header.www_authenticate) if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }
http-response deny deny_status 401 hdr WWW-Authenticate %[var(txn.auth)] if { var(txn.host) -m reg -i ^(?i)(heimdall)\.example\.com } !{ var(txn.auth_response_successful) -m bool }
2020-04-28 09:17:45 +00:00
# Authelia backend route
use_backend be_authelia if host-authelia
2021-03-18 08:56:08 +00:00
2020-04-28 09:17:45 +00:00
# Service backend route(s)
use_backend be_nextcloud if host-nextcloud
2021-02-23 23:35:04 +00:00
use_backend be_heimdall if host-heimdall
2020-04-28 09:17:45 +00:00
backend be_authelia
server authelia authelia:9091
backend be_nextcloud
2020-10-26 11:38:08 +00:00
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
2020-09-10 00:52:57 +00:00
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
2020-10-26 11:38:08 +00:00
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
2020-09-10 00:52:57 +00:00
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
2020-10-26 11:38:08 +00:00
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
2020-09-10 00:52:57 +00:00
2020-04-28 09:17:45 +00:00
server nextcloud nextcloud:443 ssl verify none
2021-02-23 23:35:04 +00:00
backend be_heimdall
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
server heimdall heimdall:443 ssl verify none
2020-04-28 09:17:45 +00:00
```
##### haproxy.cfg (TLS enabled Authelia)
2020-04-28 10:53:06 +00:00
```
2020-04-28 09:17:45 +00:00
global
2020-09-10 00:52:57 +00:00
# Path to haproxy-lua-http, below example assumes /usr/local/etc/haproxy/haproxy-lua-http/http.lua
lua-prepend-path /usr/local/etc/haproxy/?/http.lua
2020-04-28 09:17:45 +00:00
# Path to haproxy-auth-request
lua-load /usr/local/etc/haproxy/auth-request.lua
log stdout format raw local0 debug
defaults
mode http
log global
option httplog
option forwardfor
frontend fe_http
bind *:443 ssl crt /usr/local/etc/haproxy/haproxy.pem
# Host ACLs
2020-11-24 01:35:38 +00:00
acl protected-frontends hdr(host) -m reg -i ^(?i)(nextcloud)\.example\.com
2021-02-23 23:35:04 +00:00
acl protected-frontends-basic hdr(host) -m reg -i ^(?i)(heimdall)\.example\.com
2020-04-28 09:17:45 +00:00
acl host-authelia hdr(host) -i auth.example.com
acl host-nextcloud hdr(host) -i nextcloud.example.com
2021-02-23 23:35:04 +00:00
acl host-heimdall hdr(host) -i heimdall.example.com
2020-04-28 09:17:45 +00:00
2021-03-18 08:56:08 +00:00
# This is required if utilising basic auth with /api/verify?auth=basic
http-request set-var(txn.host) hdr(Host)
2020-04-28 09:17:45 +00:00
http-request set-var(req.scheme) str(https) if { ssl_fc }
http-request set-var(req.scheme) str(http) if !{ ssl_fc }
http-request set-var(req.questionmark) str(?) if { query -m found }
2021-03-05 04:18:31 +00:00
# These are optional if you wish to use the Methods rule in the access_control section.
#http -request set-var(req.method) str(CONNECT) if { method CONNECT }
#http -request set-var(req.method) str(GET) if { method GET }
#http -request set-var(req.method) str(HEAD) if { method HEAD }
#http -request set-var(req.method) str(OPTIONS) if { method OPTIONS }
#http -request set-var(req.method) str(POST) if { method POST }
#http -request set-var(req.method) str(TRACE) if { method TRACE }
#http -request set-var(req.method) str(PUT) if { method PUT }
#http -request set-var(req.method) str(PATCH) if { method PATCH }
#http -request set-var(req.method) str(DELETE) if { method DELETE }
#http -request set-header X-Forwarded-Method %[var(req.method)]
2020-09-22 23:06:26 +00:00
# Required headers
2020-04-28 09:17:45 +00:00
http-request set-header X-Real-IP %[src]
http-request set-header X-Forwarded-Proto %[var(req.scheme)]
http-request set-header X-Forwarded-Host %[req.hdr(Host)]
http-request set-header X-Forwarded-Uri %[path]%[var(req.questionmark)]%[query]
# Protect endpoints with haproxy-auth-request and Authelia
http-request lua.auth-request be_authelia_proxy /api/verify if protected-frontends
2021-02-23 23:35:04 +00:00
# Force `Authorization` header via query arg to /api/verify
2021-03-18 08:56:08 +00:00
http-request lua.auth-request be_authelia_proxy /api/verify?auth=basic if protected-frontends-basic
# Redirect protected-frontends to Authelia if not authenticated
http-request redirect location https://auth.example.com/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query] if protected-frontends !{ var(txn.auth_response_successful) -m bool }
# Send 401 and pass `WWW-Authenticate` header on protected-frontend-basic if not pre-authenticated
http-request set-var(txn.auth) var(req.auth_response_header.www_authenticate) if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }
http-response deny deny_status 401 hdr WWW-Authenticate %[var(txn.auth)] if { var(txn.host) -m reg -i ^(?i)(heimdall)\.example\.com } !{ var(txn.auth_response_successful) -m bool }
2020-04-28 09:17:45 +00:00
# Authelia backend route
use_backend be_authelia if host-authelia
2021-03-18 08:56:08 +00:00
2020-04-28 09:17:45 +00:00
# Service backend route(s)
use_backend be_nextcloud if host-nextcloud
2021-02-23 23:35:04 +00:00
use_backend be_heimdall if host-heimdall
2020-04-28 09:17:45 +00:00
backend be_authelia
server authelia authelia:9091
backend be_authelia_proxy
mode http
server proxy 127.0.0.1:9092
listen authelia_proxy
mode http
bind 127.0.0.1:9092
server authelia authelia:9091 ssl verify none
backend be_nextcloud
2020-10-26 11:38:08 +00:00
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
2020-09-10 00:52:57 +00:00
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
2020-10-26 11:38:08 +00:00
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
2020-09-10 00:52:57 +00:00
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
2020-10-26 11:38:08 +00:00
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
2020-09-10 00:52:57 +00:00
2020-04-28 09:17:45 +00:00
server nextcloud nextcloud:443 ssl verify none
2021-02-23 23:35:04 +00:00
backend be_heimdall
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
server heimdall heimdall:443 ssl verify none
2020-04-28 09:17:45 +00:00
```
[HAproxy]: https://www.haproxy.org/