{"id":306,"date":"2023-07-21T16:47:30","date_gmt":"2023-07-21T16:47:30","guid":{"rendered":"https:\/\/wp.bebubi.com\/?p=306"},"modified":"2023-10-25T03:47:25","modified_gmt":"2023-10-25T03:47:25","slug":"wordpress-behind-haproxy-with-tls-terminationwordpress-behind-haproxy","status":"publish","type":"post","link":"https:\/\/bebubi.com\/index.php\/2023\/07\/21\/wordpress-behind-haproxy-with-tls-terminationwordpress-behind-haproxy\/","title":{"rendered":"WordPress behind HAProxy with TLS termination"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;oxcrag.net\/2017\/04\/30\/wordpress-behind-haproxy-with-tls-termination\/<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">TLS termination configuration<\/h1>\n\n\n\n<p>The problem with terminating TLS traffic before the web server, is that any good web application should be able to recognize that the client is coming from an insecure connection. Luckily, we can use HAProxy to tell WordPress that the connection was good up until the load balancer and to trust it the rest of the way. Be aware that this is an extremely bad idea if there is any way to reach the web server other than via your HAProxy:<\/p>\n\n\n\n<p><em>\/usr\/share\/wordpress\/wp-config.php:<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[...]\n\/** Make sure WordPress understands it's behind an SSL terminator *\/\ndefine('FORCE_SSL_ADMIN', true);\ndefine('FORCE_SSL_LOGIN', true);\nif ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')\n$_SERVER['HTTPS']='on';\n[...]<\/pre>\n\n\n\n<p><em>\/etc\/haproxy\/haproxy.cfg:<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[...]\nfrontend web-https\n    option http-server-close\n    http-request set-header X-Forwarded-Proto https if { ssl_fc }\n[...]<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">global\n\tlog \/dev\/log\tlocal0\n\tlog \/dev\/log\tlocal1 notice\n\tchroot \/var\/lib\/haproxy\n\tstats socket \/run\/haproxy\/admin.sock mode 660 level admin expose-fd listeners\n\tstats timeout 30s\n\tuser haproxy\n\tgroup haproxy\n\tdaemon\n\n\t# Default SSL material locations\n\tca-base \/etc\/ssl\/certs\n\tcrt-base \/etc\/ssl\/private\n\n\t# modern configuration\n\tssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256\n\tssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets\n\n\tssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256\n\tssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets\n\n\ndefaults\n\tlog\tglobal\n\tmode\thttp\n\toption\thttplog\n\toption\tdontlognull\n\n\toption forwardfor\n\toption http-server-close\n\n        timeout connect 5000\n        timeout client  50000\n        timeout server  50000\n\terrorfile 400 \/etc\/haproxy\/errors\/400.http\n\terrorfile 403 \/etc\/haproxy\/errors\/403.http\n\terrorfile 408 \/etc\/haproxy\/errors\/408.http\n\terrorfile 500 \/etc\/haproxy\/errors\/500.http\n\terrorfile 502 \/etc\/haproxy\/errors\/502.http\n\terrorfile 503 \/etc\/haproxy\/errors\/503.http\n\terrorfile 504 \/etc\/haproxy\/errors\/504.http\n\nfrontend stats\n        bind *:9000\n        mode http\n        log global\n        maxconn 10\n\n        stats enable\n        stats refresh 10s\n        stats show-node\n        stats auth nguyen:Anne1021\n        stats uri  \/\n\nfrontend www-http\n\tbind *:80\n\tbind *:443 ssl crt \/etc\/haproxy\/ssl\/\n\thttp-request set-header X-Forwarded-Proto https if { ssl_fc }\n\n\t# letsencryp validation path for cert request\n\tacl letsencrypt-acl path_beg \/.well-known\/acme-challenge\/\n\n\tacl wp_site hdr(host) -i bebubi.com\n        acl wp_site hdr(host) -i www.bebubi.com\n        acl wp_site hdr(host) -i wp.bebubi.com\n        acl wp_site hdr(host) -i bibube.com\n        acl wp_site hdr(host) -i www.bibube.com\n        acl wp_site hdr(host) -i wp.bibube.com\n\n        acl nc_site hdr(host) -i nc.bibube.com\n        acl nc_site hdr(host) -i nc.bebubi.com\n\n\tuse_backend letsencrypt-backend if letsencrypt-acl\n\tuse_backend wp-backend if wp_site\n\tuse_backend nc-backend if nc_site\n\n\nbackend letsencrypt-backend\n\tserver letsencrypt 127.0.0.1:8888\n\nbackend wp-backend\n\tserver wp 192.168.0.201:80\n\nbackend nc-backend\n\tserver nc 192.168.0.200:443 check ssl verify none<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"> Installing Let\u2019s Encrypt Client<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo add-apt-repository ppa:certbot\/certbot\nsudo apt-get update\nsudo apt-get install certbot<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Obtaining a Certificate<a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-secure-haproxy-with-let-s-encrypt-on-ubuntu-14-04#step-2-obtaining-a-certificate\"><\/a><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">Verify Port 80 is Open\n\nThen\nsudo certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d bibube.com -d wp.bibube.com -d nc.bibube.com -d www.bibube.com\n\nsudo certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d bebubi.com -d wp.bebubi.com -d nc.bebubi.com -d www.bebubi.com\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Automated renewal script<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">root@pi-haproxy:~# cat renewCerts\n#!\/bin\/bash\ncertbot renew --force-renewal --standalone --preferred-challenges http --http-01-address 127.0.0.1:8888\n\n# Loop through all Let's Encrypt certificates\nfor CERTIFICATE in `find \/etc\/letsencrypt\/live\/* -type d`; do\n\n  CERTIFICATE=`basename $CERTIFICATE`\n\n  # Combine certificate and private key to single file\n  cat \/etc\/letsencrypt\/live\/$CERTIFICATE\/fullchain.pem \/etc\/letsencrypt\/live\/$CERTIFICATE\/privkey.pem &gt; \/etc\/haproxy\/ssl\/$CERTIFICATE.pem\n\ndone\nsystemctl reload haproxy.service<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>TLS termination configuration The problem with terminating TLS traffic before the web server, is that any good web<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-306","post","type-post","status-publish","format-standard","hentry","category-work"],"_links":{"self":[{"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/posts\/306","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/comments?post=306"}],"version-history":[{"count":0,"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/posts\/306\/revisions"}],"wp:attachment":[{"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/media?parent=306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/categories?post=306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bebubi.com\/index.php\/wp-json\/wp\/v2\/tags?post=306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}