Setup & Configure HAProxy Container with Cloudflare Origins
This is the second guide in the series on how I setup my homelab. In my setup I use Cloudflare Origin Server between the world and my home server. My instructions will include all of the necessary configuration besides the required port forwards on your router. In my setup I only foward connections on port 443 from Cloudflares IPv4 ranges.
Requirements
- Cloudflare account
- Public domain name
- Port 443 forwarded on your router to your LXD server.
Create HAProxy Incus Container
To create the containers run the following.
1
incus launch images:debian/12 haproxy
This will create a new container with the name haproxy using a Ubuntu 22.04 image.
Incus configuration
For this to work port 443 needs to be forwarded to the haproxy container. To do this you need haproxy to have a static IP.
1
2
incus config device override haproxy eth0 ipv4.address 10.10.10.254
incus restart haproxy
You need to forward HTTPS traffic from the host to the container. This creates a rule in nftables to pass the traffic through. You need to use your Incus hosts IP address for the listen address. Make sure your server has a static IP, in my example the server’s IP is 10.0.2.15.
1
incus config device add haproxy https proxy listen=tcp:10.0.2.15:443 connect=tcp:10.10.10.254:443 nat=true
At this point all the configuration requirements for the container are complete. IF you want to view the configuration you can do the following.
incus config show haproxy
And the output will look similar to this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
architecture: x86_64
config:
image.architecture: amd64
image.description: Debian bookworm amd64 (20240416_05:24)
image.os: Debian
image.release: bookworm
image.serial: "20240416_05:24"
image.type: squashfs
image.variant: default
volatile.base_image: e763cf30d37fa3a77d7c4ed0f74c084ad9480e0ec70ff515426e67a8225317c4
volatile.cloud-init.instance-id: b4a2b8ba-0ccb-4cde-84a3-e11be74d00d5
volatile.eth0.host_name: veth042b3414
volatile.eth0.hwaddr: 00:16:3e:58:ab:47
volatile.idmap.base: "0"
volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"I
sgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgi
d":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
volatile.last_state.idmap: '[]'
volatile.last_state.power: RUNNING
volatile.uuid: 2ca6366b-2884-4c46-9791-d28619678059
volatile.uuid.generation: 2ca6366b-2884-4c46-9791-d28619678059
devices:
eth0:
ipv4.address: 10.10.10.254
name: eth0
network: lxdbr0
type: nic
https:
connect: tcp:10.10.10.254:443
listen: tcp:10.0.2.15:443
nat: "true"
type: proxy
ephemeral: false
profiles:
- default
stateful: false
description: ""
Install and Configure HAProxy
To change to the terminal of the HAProxy container you can do the following.
incus exec haproxy bash
Now I update apt repositories and install all updates. Then install haproxy.
1
2
3
apt update
apt full-upgrade
apt install haproxy
We need to configure the haproxy.cfg. For a write-up of my complete finalised HAProxy configuration click here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
user haproxy
group haproxy
daemon
maxconn 40000
ulimit-n 81000
crt-base /etc/haproxy/certificates/
defaults
mode http
option httplog
option dontlognull
option forwardfor
log global
timeout client 30s
timeout server 30s
timeout connect 5s
# HTTP Frontend
frontend fe_http
bind *:80
http-request redirect scheme https code 301
# HTTPS Frontend
frontend fe_https
bind *:443 ssl crt domain.com.pem
acl service ssl_fc_sni service.domain.com
use_backend be_service if service
# This redirects to a failure page
default_backend be_no-match
backend be_no-match
http-request deny deny_status 403
backend be_service
server service service.lxd:80 check
When we add other containers with services I will show how to configure this file for access to the services.
Configure Cloudflare
Edge Certificate
When you sign up to Cloudflare with your domain you receive a Universal SSL certificate which is enabled by default. I am not sure what the default settings are but mine is set as follows but you can decide how you want to manage it. If you need backwards compatibility for TLS, you can set those setting as you please.
Always Use HTTPS: True
Minimum TLS Version: TLS 1.3
Opportunistic Encryption: True
TLS 1.3: True
Automatic HTTPS Rewrites: True
Origin Certificate
This is the certificate you will install into your haproxy. For an explanation please read through the Cloudflare documentation for this here.
Here are the instuctions to create an Origin CA certificate from Cloudflare docs
After the Origin Certificate is created you will be taken to a page that shows the Origin Certificate and the Private Key.
We will paste both sections of those into a single PEM file on the HAProxy server.
You will need to make a directory called certificates under /etc/haproxy
and create a file using your editor of choice
1
2
mkdir /etc/haproxy/certificates
vim /etc/haproxy/certificate/domain.com.pem
Paste in the Origin Certificate and Private Key. It will look something like this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
-----BEGIN CERTIFICATE-----
MIIEpAIBAAKCAQEArxHLfi123Z1mIM7H4xKsDwbxfVvsPVxSuwR3kxLD1nJE/YCp
pTF/IJHNVFd1eR/PRv2P5i8i8c/u5++p4NC7nonZv0w1dDQTcIXx9Q9BfLytO4Al
u/sz6qZ3F9gEEQFnaaZPHkpYoWq95JMIKxx6rrnpW6VUz/4+b3Uxu1wdJ9LeGXtf
ypvmbXmuvakmGz7CGxhWYNZ6JsoqkBTLR61LjUHrg1G2HexrNv1iWFx4GhWn8wXE
b8uDUp/xbsLEQM3V4z7LCAqLhh/elKG/TzKekU1QrJC1pwyKRUJ6+MryITEUkH5K
9m/y4W7e27wP5AwPBctoKJDVerfuFopQMJ8qgQIDAQABAoIBAQCAqS9IF9mXnSmF
SvKT6xEQKiYn3vqLTeJvFyVZrRzH6UrSk1AZ23p2UTD5nxzyW3JV1dt/a3zfAdWu
FvBeDIkWRnEEqdlPAUaYF5huZTvXlEIrzE3vDPpmpNg5acPzS3jYqCTVOgZQ+sV7
yqLiLBfteSwK8kKWaV8xQou+CkBTFuoA3SJqTH3P+G0IEWEPJ3llM1lJQq1J4TrV
1zz7DrB/xvIB2+ZyD5mS338geVJs2QLu7m/UvERNf6wqQzlxGLNv0r1pmbwjcKTw
vUI71CU5ETtY0XZQ/B9DfWoc0InHRo+9KzvqX03SUz1LjMNOoBF+2G57jSgk/81/
UmhstL8BAoGBAN/63GnQddLPkAuG+uQ9UA3CSd/CsAYxFyZFW0pIylLzyK5HWZRm
dlQ6fJHFA3P3KR79llxQmCseKCAOJPoEkmEiMKEPpqNXq3yFMc5IEuCuhe/KIKv6
NQYiS8DuGn7y/LYIBN8mM3WXhFAyPCNM/UVAVO/LhGhEGKlKhCPfslRJAoGBAMgY
7Xr8r0ABuD5fGxBDTPNA8rMZ6K1W48j1TzTppiAWuSkeC5rZgpJeySIL9Q3iMCqa
pQ3VBYBALszA6McsCp4PlKx85DS8JymFUO14tQzMkdIQyBqrs7ur6+rzZQu0p8cN
VnvrpT1kRhubDYFVR88HTAFo9NmhphSEwj8dgrR5AoGAThwHF+O54z29Zze4cTYs
n8+8wYr8pfwirZcMYhiGbm1T8+swAz/ETlVjMda6AIwWTBd1g1Yb6xWGOr+UB5jm
j3dD7DcwDtC5HiC5IM4jvzU9wkUEJdWI/k2hi3O9y73jgXvEbym8Umr3mpwaOtlT
jf4EYOfhkhcFXqx87qHJZ/kCgYA7EGihIg9U9Gz/NDGX5lXDhAtf5Kjy6bAJNKfx
tXpNBIgZY/4G8meBbystupvWQkr3eHh6EcQy7D8kP1k22YA00eKP27m8+0EQF4Mg
5b2DjqsId92pSb+fCQt1ae0MvIG91ukNYSyAZ6XuJiGhaJvut3eu/t0vlHCio+F2
oe5f+QKBgQDIPi0Rah6OMvqMj5S4aPlC6/TCYIbDyK0wplFdO+a4sLiI/Nlds2ck
p5NXuveBBTBdCbQ6iv02Ultt2GXo7Kv/GIGAUI6z0238bnoVvtoLeN7slkC1Wptc
Ec8pgt0KyGKzCFH2gtIeUl/04RKEIjyAv/7D3gd1d0W6Fo9xE7v4yg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEogIBAAKCAQEAiocVnTHMYU2ItRCsQOpl4b5zsRBHyncJ5nDzTJg771xRMzwV
8c1uN2JwvO5smo/Tc1Ri4Od0WFN5HZnsYMhWayyHKVWyCEGLpMWQBSH9wKR+hYMD
6NiMAfYpEqWAB4TALRK2fhwYVXFXM1RLQlP4YP0q7ZfmEYFeq9aAgDJN0I3HThTQ
4iLEdzoI2Ak6HFAQxpGFFcVq/hhygu4WWX/LyM4rrajkM6MEb+gxWjNfZUu6M3NS
1W6v5ryZn43SzF0GJLTiPPFapQ5XIxsbMr781hVHzOaa/p8u+eGTb5n3ZphbkM2Q
uscU/YD+ElUobc74QGma+MXxssRzQvHUwEOIzwIDAQABAoIBABi1o8tYWKZ6mAoE
IVWq+eVcfXJ1/vhEZ4WtXBirhvVZODq1Wwy4ohJLAuUQelrPkN4fjUukvYIL0azQ
CfPxiEixtqJO4OTMHEaV3uyrdYHpVZAnIIlmJwMqj4T99Gpi6Yygq+CuzkBfaTiE
rq/0HnfecMvUrnss4mAwcNdtIagzfnHaf3DcSZwIyoRniMQQKxvdhRuSM+n1qar7
GQIqWHMS0qIofYOvTjIByWfp/IyY8ltTzmEJgyaFcrT0tC+WJ2XC4hbYddRRTWAf
OoZhtbsQUY8lfUiGXB4G+FFSVcvOgR4la0+MKYHvr15bKAp2nJ6hhwM/J9mTm0I7
JFb5TMECgYEA0Lon/8sTVvubrHT44R91ScSYp9qyrPzICLgIttzPyzoq3LrNGwlu
v790AWe0n8uUfkM42TcodJCbn3VCL6O6mtQgfHXt+3A7xaI6pON9r8E927XwsCpq
XJpfzWYktMDafTB6ltmd4EWKM1/igXGjKkdZRJ8rV/Zefu8Ff5Z6918CgYEAqebQ
c3a4pz7coTYgOH+ST0NOHijTEi56r8SSgddGsrJko8Oem2RZoXf/nAwskrHQ1cuQ
2fSliEn7zzv1gVcYyLG3vvTQYEjFCp4qHc1YP7S/UdKRnDYD7dN15ZCxPUHU4t+L
wBaxnSzKkicdUyntBKZIO0QNMjmVzrVz60z2FJECgYAxOoaulNXl4QfxX9FHP2Up
Vd3vUOxtUl1XeRhNEL1NoFV1o/U2GD5vqRcSMcRvH9PRB8fDq3e2LlkV/dDzbXlY
hQl4cVQExo7CaSXNt/3v0vLk+/9dfVOCrcJErn+fxhCCEEoJhB/xQlV7EnVYtFWY
ZiWOwr+1Sl01MOiqE/LCnwKBgB7oQC9g/4JdKyGgiQf+HQ2SPtm5r3v1PJhQ+B3q
nY/QaAJqiaXXAX8gJz2p8UnWUxkxaO5dVOeQHeC7FZQr1fRccAKq4mVBl6aw0xSM
0Gr2ZH9sANUb9mcDOsVCJxvvp9yFshSFjFX9WfRwbSM900IvRaCSZpwmYZwy4h2B
6JohAoGAEjNEnQmjno4cXLBrcOnHblZhM3YyD81fCZ620wzTSPneOeOaFPOQaDLk
V+8t/qJ2h2Z+SszWtB8GgtkRSmotWv+QPXkxfMi/WMMKcEOHATg+D64wuWTLToJf
9ABFk+hNCdW5cLNnBqOwgYzKSniYsx/j+Y/Z9hXbgoPXwyWT7vY=
-----END PRIVATE KEY-----
You are now ready to create your first web service container.