WIUNIX ACADEMY
HAProxy with Let’s Encrypt and validated certificate renewal
Page 4 of 4. Review the earlier steps and prerequisites before continuing.
YOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
USE YOUR OWN VALUES
Configure this tutorial
Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.
Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.
Set values for my environment7 editable values
LET’S BUILD
Enable scheduling and monitor the served expiry
Enable the dedicated units after successful manual probes. Monitor timer failures, Certbot logs, the actual served certificate fingerprint/expiry and backend readiness from outside the edge. A timer listed as active does not prove issuance, successful hook execution or the loaded certificate. Maintain a protected off-host backup of ACME account/lineage, configs and the last trusted PEM; no restore drill or reboot was performed for this article. A deploy-hook error does not necessarily make issuance or the overall Certbot exit code fail; inspect its journal and the actually served certificate independently.
Bash on dedicated edge VM; external checks noted in text
set -euo pipefailo pipefail
sudo systemctl daemon-reload
sudo systemctl enable academy-haproxy.service academy-acme-webroot.service
sudo systemctl enable --now academy-certbot.timer
sudo systemctl list-timers --all academy-certbot.timer
sudo journalctl -u academy-certbot.service -n 60 --no-pager
openssl s_client -connect 'app.example.com:443' -servername 'app.example.com' -verify_hostname 'app.example.com' -verify_return_error -CApath /etc/ssl/certs </dev/null 2>/dev/null | openssl x509 -noout -dates -fingerprint -sha256
The next trigger is visible; trusted public certificate dates/fingerprint are observable and alert ownership is assigned.
LET’S BUILD
Diagnose the failing boundary without hiding it
For authorization errors compare public A/AAAA, exact token bytes, CAA and external port80 reachability before retrying. A404 indicates routing/webroot; a308 on the token indicates the exception is wrong. For503 inspect both readiness responses and firewall/source policy. Do not weaken checks to make an unhealthy dependency appear healthy. For TLS errors inspect chain/SAN/key/permissions and the selected SNI; never use curl -k as acceptance. For hook failure compare current lineage and served fingerprint, repair the hook and redeploy the already renewed certificate.
Bash on dedicated edge VM; external checks noted in text
sudo haproxy -c -f '/srv/academy-haproxy-tls/haproxy.cfg'
sudo journalctl -u academy-haproxy.service -u academy-acme-webroot.service -u academy-certbot.service -n 100 --no-pager
sudo ss -lntp
sudo stat -c '%a %U:%G %n' '/srv/academy-haproxy-tls/certs' '/srv/academy-haproxy-tls/certs/app.example.com.pem'
curl --fail -H 'Host: app.example.com' 'http://10.77.0.21:8080/health/ready'
curl --fail -H 'Host: app.example.com' 'http://10.77.0.22:8080/health/ready'
dig CAA 'app.example.com'
Logs and probes identify DNS/challenge, TLS/deploy or backend failure separately; failing commands remain visible.
LET’S BUILD
Restore the last trusted PEM deliberately
Pause only this timer during investigation. Use the previous PEM only if it still covers the hostname and has not expired/revoked; it contains a private key and stays0600. Copy it to a new candidate, validate the candidate with the active config, then swap and reload. Retain failed material privately for diagnosis. Do not repeat this over a known good deployment or run it on the initial HTTP-only stage.
Bash on dedicated edge VM; external checks noted in text
set -eu
sudo systemctl stop academy-certbot.timer
sudo openssl x509 -in '/srv/academy-haproxy-tls/certs/app.example.com.previous.pem' -checkend 86400 -checkhost 'app.example.com' -noout
sudo install -m 0600 '/srv/academy-haproxy-tls/certs/app.example.com.previous.pem' '/srv/academy-haproxy-tls/certs/rollback.pem'
sudo python3 - <<'PY'
from pathlib import Path
root=Path('/srv/academy-haproxy-tls')
s=(root/'haproxy.cfg').read_text()
old=str(root/'certs/app.example.com.pem')
assert s.count('crt '+old)==1
(root/'rollback.cfg').write_text(s.replace('crt '+old,'crt '+str(root/'certs/rollback.pem')))
PY
sudo haproxy -c -f '/srv/academy-haproxy-tls/rollback.cfg'
sudo mv '/srv/academy-haproxy-tls/certs/rollback.pem' '/srv/academy-haproxy-tls/certs/app.example.com.pem'
sudo haproxy -c -f '/srv/academy-haproxy-tls/haproxy.cfg'
sudo systemctl reload academy-haproxy.service
curl --fail --show-error 'https://app.example.com/'
The chosen still-trusted previous PEM validates and is served after reload; timer stays paused until the root cause is repaired.
LET’S BUILD
Recover a failed first TLS activation
Only if the initial TLS reload failed, restore the saved HTTP bootstrap. This intentionally removes HTTPS and preserves HTTP-01 during repair; it is not a way to serve the application securely. After repair repeat the candidate validation/activation, trusted TLS probe and hook probe, then resume the dedicated timer. To end the disposable lab, stop/disable its four named units through normal service management and archive protected files before removing only this root; never remove distro configs or public DNS records used by others.
Bash on dedicated edge VM; external checks noted in text
set -eu
sudo haproxy -c -f '/srv/academy-haproxy-tls/haproxy.bootstrap.cfg'
sudo install -m 0644 '/srv/academy-haproxy-tls/haproxy.bootstrap.cfg' '/srv/academy-haproxy-tls/haproxy.cfg.next'
sudo mv '/srv/academy-haproxy-tls/haproxy.cfg.next' '/srv/academy-haproxy-tls/haproxy.cfg'
sudo systemctl reload academy-haproxy.service
curl --fail --resolve 'app.example.com:80:192.0.2.10' 'http://app.example.com/.well-known/acme-challenge/academy-probe'
Only the bootstrap is loaded and the probe still returns its exact public token body.
What this guide actually tested
All OS paths are documentation-reviewed, not installations. The isolated fixture evidence is recorded after execution below; public ACME issuance, account registration, DNS changes, renewal with a real CA, systemd boot/reboot, HA and backup restore are not claimed. Reader personalization changes text/copy panels only and does not test your network.
Design resilience after proving the single edge
Keep readiness semantics, renewal alerts and private key backups under a named operator. For redundant edges, design challenge distribution, certificate custody, state and failover separately; copying this VM twice does not create HA. Continue with the existing HAProxy/Keepalived guide only after understanding its network and split-brain limits.
GO TO THE SOURCE
Official references
Each environment states how it was reviewed. A documentation review does not claim a hands-on test of every version.
KEEP LEARNING