HAProxy is a battle-tested, high-performance load balancer and proxy that can serve as an alternative frontend for NaïveProxy. Compared to the Caddy-based setup, the HAProxy approach is more complex — it involves separate tools for certificate management, the forward proxy backend, and TLS termination — but it is widely used in production environments and offers granular control over routing and authentication. This guide walks through each component in order.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/klzgrad/naiveproxy/llms.txt
Use this file to discover all available pages before exploring further.
HAProxy requires certificates in a bundled PEM format and benefits from serving both an ECC and an RSA certificate for maximum client compatibility. Use acme.sh to issue and install both.
site=example.org
acme.sh -k ec-256 -d $site -d www.$site --issue -w /var/www/html
acme.sh -k 2048 -d $site -d www.$site --issue -w /var/www/html
mkdir -p /etc/haproxy/certs
acme.sh --install-cert --ecc -d $site \
--key-file /tmp/$site.key \
--fullchain-file /tmp/$site.crt \
--reloadcmd "cat /tmp/$site.* >/etc/haproxy/certs/$site.pem.ecdsa; rm /tmp/$site.*; service haproxy restart"
acme.sh --install-cert -d $site \
--key-file /tmp/$site.key \
--fullchain-file /tmp/$site.crt \
--reloadcmd "cat /tmp/$site.* >/etc/haproxy/certs/$site.pem.rsa; rm /tmp/$site.*; service haproxy restart"
The
--reloadcmd concatenates the key and full-chain into a single PEM file that HAProxy can read, then restarts HAProxy automatically whenever acme.sh renews the certificate.tinyproxy acts as the local forward proxy backend that HAProxy routes authenticated requests to. It listens only on localhost so it is never directly reachable from the internet.
User tinyproxy
Group tinyproxy
PidFile "/run/tinyproxy/tinyproxy.pid"
MaxClients 100
MinSpareServers 5
MaxSpareServers 20
StartServers 10
Port 8888
Listen 127.0.0.1
LogFile "/dev/null"
DisableViaHeader Yes
Listen 127.0.0.1 — Binds only to localhost; tinyproxy is never exposed directly.DisableViaHeader Yes — Suppresses the Via header that would reveal a proxy is in the path.LogFile "/dev/null" — Discards logs to avoid recording user activity.Check the NaïveProxy issues for the currently tested and recommended HAProxy version before installing.
userlist users
user name insecure-password pass
frontend haproxy_tls
bind :443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
option http-use-proxy-header
acl login base_dom login-key.test
acl auth_ok http_auth(users)
http-request auth if login !auth_ok
http-request redirect location https://google.com if login auth_ok
use_backend proxy if auth_ok
default_backend masquerade
backend proxy
http-request del-header proxy-authorization
server proxy 127.0.0.1:8888
backend masquerade
server nginx 127.0.0.1:80
userlist users block defines the credentials HAProxy checks against.frontend haproxy_tls block terminates TLS on port 443, advertising both HTTP/2 and HTTP/1.1 via ALPN, and loading all certificate PEM files from /etc/haproxy/certs/.login ACL matches requests to your secret login domain (e.g. login-key.test). Visiting that domain in a browser triggers an HTTP auth prompt; a successful login redirects to google.com.Proxy-Authorization credentials are routed to the proxy backend (tinyproxy on port 8888). The Proxy-Authorization header is stripped before forwarding.masquerade backend, which serves your regular website from a local web server on port 80.Replace
name, pass, and login-key.test with values that are hard to guess. Anyone who knows these values can use your proxy or confirm its existence.To authenticate from a browser, visit
https://login-key.test (the https:// scheme is required — http:// will not work through HAProxy’s TLS frontend).HTTPS proxying on Android via the system WiFi proxy setting requires a PAC (Proxy Auto-Config) file URL rather than a direct proxy address.
acl pac path /proxy-key.pac
errorfile 200 /etc/haproxy/errors/proxy.pac.http
http-request deny deny_status 200 if pac
HTTP/1.0 200 OK
Cache-Control: no-cache
Connection: close
Content-Type: text/plain
function FindProxyForURL(url, host) {
if (shExpMatch(host, "localhost")) return "DIRECT";
if (shExpMatch(host, "192.168.*")) return "DIRECT";
if (shExpMatch(host, "127.0.*")) return "DIRECT";
return "HTTPS example.org";
}
Next Steps
- For the simpler, Caddy-based setup that handles certificates automatically, see Caddy Setup.
- To run Caddy as a persistent systemd service, see Run as Daemon.