NaiveProxy Caddy Setup: Authentication and Updates

NaiveProxy Caddy Setup: Authentication and Updates

Marcus Reid
October 11, 2026· 11 min read

A NaiveProxy Caddy setup needs a compatible forward-proxy server, a trusted certificate, and a client that forwards only the applications you select. This guide uses Ubuntu 24.04 LTS x64 on both ends, the official NaiveProxy client v154.0.8037.49-4, and the prebuilt Naive Caddy v2.11.7-naive. These are documentation reference versions, not versions tested here.[1][2]

Key Takeaways

  • Use the project's Naive-compatible Caddy build; an ordinary Caddy binary is insufficient.
  • Keep client credentials in a private file and the SOCKS listener on loopback.
  • Test authorized forwarding, incorrect credentials, and unauthenticated CONNECT separately.
  • Initial certificate issuance does not establish that renewal works.
  • Keep a recoverable configuration and follow Chromium and Caddy security updates.

This procedure is based on the official sources below; a complete end-to-end test has not been performed. The tables describe checks and expected behavior, not observed results. Start with the self-hosting ownership and recovery checklist.

What does this NaiveProxy Caddy setup require?

Use a server you administer, an independently verified SSH host key, and provider-console access if networking fails. Connect with strict host-key checking and a project-specific known_hosts populated through a trusted, separate channel. Stop on unknown, changed, or revoked keys. Do not replace verification with a successful password login.

You also need a domain you control, working DNS, and the ability to serve TCP ports 80 and 443. This route uses HTTPS over TCP; it does not configure QUIC. A public certificate must cover proxy.example.com. Replace every example hostname, email address, username, and password before use. Publish an AAAA record only if the server actually serves the required IPv6 path.

Decide whether operating an OS and a Chromium-derived client serves your task. If you only need an everyday internet exit, compare VPS and VPN responsibilities before adopting this maintenance workload. NaiveProxy is an application-proxy implementation; the Xray and V2Ray core explanation helps distinguish that role from an entire device-routing solution.

Record the baseline

On a fresh, dedicated server, record OS/architecture, existing listeners, firewall rules, and any certificate service. Back up configuration and certificates with access restricted to administrators. Run ss -lntup with sufficient privileges and identify the owners of ports 80 and 443. If either is occupied, resolve ownership first; do not stop an unrelated service to make this example fit.

Keep SSH allowed from your management address. Add only the required TCP rules in both the host firewall and provider firewall. Do not disable either firewall. Verify system time and CA packages on both machines; incorrect time can break certificate validation.

Step 1: Install the official server and isolate its files

Download the Linux amd64 server asset from the pinned forwardproxy release and the matching Linux x64 client archive from the NaiveProxy release. Use those official release pages, review their notes and any published integrity information, and unpack into private staging directories. Do not execute a downloaded shell installer. The client release recommends this Naive Caddy server version.[1][2]

The following commands assume the extracted server executable is ./caddy and that the dedicated naive-caddy account does not already exist. Inspect an existing account instead of changing its ownership blindly.

sudo useradd --system --home-dir /var/lib/naive-caddy --shell /usr/sbin/nologin naive-caddy
sudo install -d -o root -g root -m 0755 /opt/naive-caddy/v2.11.7-naive
sudo install -o root -g root -m 0755 ./caddy /opt/naive-caddy/v2.11.7-naive/caddy
sudo install -d -o root -g naive-caddy -m 0750 /etc/naive-caddy
sudo install -d -o naive-caddy -g naive-caddy -m 0700 /var/lib/naive-caddy
sudo install -d -o root -g root -m 0755 /var/www/naive-site
/opt/naive-caddy/v2.11.7-naive/caddy version
/opt/naive-caddy/v2.11.7-naive/caddy list-modules

Require the expected version and http.handlers.forward_proxy module. The daemon can write certificate state, but cannot replace its root-owned executable or configuration. Caddy needs persistent writable storage for certificate management; avoid temporary homes or clearing its state during routine maintenance.[3]

Step 2: Configure NaiveProxy authentication and HTTPS

Generate a separate random username and password using a password manager or openssl rand -hex 24. Hex avoids URL escaping ambiguity. Save them privately; never paste real values into shell arguments, screenshots, tickets, or shared logs. With sudoedit, create /etc/naive-caddy/Caddyfile:

{
    order forward_proxy before file_server
    log {
        exclude http.log.error
    }
}
:443, proxy.example.com {
    tls admin@example.com
    forward_proxy {
        basic_auth REPLACE_USER REPLACE_PASSWORD
        hide_ip
        hide_via
        probe_resistance
    }
    file_server {
        root /var/www/naive-site
    }
}

Keep :443 first as required by the project's server example. probe_resistance changes how unauthenticated probes are handled; a normal-looking response is not evidence that CONNECT forwarding is authorized. Serve only a deliberately public static page from the web root, with no secrets or directory contents you would not publish.[4]

Protect and validate the file before starting a listener:

sudo chown root:naive-caddy /etc/naive-caddy/Caddyfile
sudo chmod 0640 /etc/naive-caddy/Caddyfile
sudo -u naive-caddy /opt/naive-caddy/v2.11.7-naive/caddy validate --config /etc/naive-caddy/Caddyfile --adapter caddyfile

Validation checks configuration provisioning; it does not prove certificate issuance or forwarding. A failure here is a stop condition. Check the build, module, syntax, and read permissions before proceeding.

Step 3: Start the service and a loopback client

Create /etc/systemd/system/naive-caddy.service as root. This dedicated unit grants the low-port binding capability instead of running the daemon as root. The data directory stays stable across restarts. Caddy documents systemd as a service-management route.[3]

[Unit]
Description=Naive Caddy proxy
After=network-online.target
Wants=network-online.target

[Service]
User=naive-caddy
Group=naive-caddy
Environment=HOME=/var/lib/naive-caddy
WorkingDirectory=/var/lib/naive-caddy
ExecStart=/opt/naive-caddy/v2.11.7-naive/caddy run --config /etc/naive-caddy/Caddyfile --adapter caddyfile
ExecReload=/opt/naive-caddy/v2.11.7-naive/caddy reload --config /etc/naive-caddy/Caddyfile --adapter caddyfile
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/naive-caddy
Restart=on-failure
RestartSec=5
UMask=0077

[Install]
WantedBy=multi-user.target

Run sudo systemctl daemon-reload, then sudo systemctl enable --now naive-caddy. Inspect systemctl status naive-caddy and administrator-only journal output. Check listener ownership. Certificate errors require fixing DNS, port reachability, permissions, or time; do not add an insecure client option.

On the Ubuntu client, install the extracted naive binary in a root-owned, version-specific directory such as /opt/naive-client/v154.0.8037.49-4/naive. Create a user-owned directory with mode 0700 and a mode-0600 config.json containing:

{
  "listen": "socks://127.0.0.1:1080",
  "proxy": "https://REPLACE_USER:REPLACE_PASSWORD@proxy.example.com"
}

Run the executable with the private configuration path as its argument, without putting credentials on the command line. Leave it in the foreground for this first trial. Configure only a test application to use SOCKS5 127.0.0.1:1080; preserve its previous setting. The TUN and system-proxy comparison explains why other applications remain outside this listener's scope.

How do you verify forwarding and refusal?

Use a small HTTPS endpoint you own for repeatable checks. For curl, explicitly select SOCKS and prevent NO_PROXY from bypassing it:

curl --fail --show-error --noproxy '' --proxy socks5h://127.0.0.1:1080 https://check.example.net/health

Replace the endpoint with your authorized destination. socks5h requests proxy-side hostname resolution for this curl request. It says nothing about another application's DNS behavior. Inspect protected logs without publishing credentials or browsing destinations.

For each client-copy negative test, stop the previous foreground trial client, start only the changed copy on the same local port, and confirm that this process owns the listener. Change one variable at a time; restore the valid file and repeat a positive request before the next case.

Check methodExpected behaviorFailure action
Correct private client configurationControlled destination returns its expected bodySeparate local listener, server TLS, authentication, and destination failures
Copy config; replace only password with another valid hex valueProxy forwarding failsIf it still succeeds, check process/config selection and bypass before exposing service
Unauthenticated HTTPS-proxy CONNECT using curlNo authorized tunnel reaches the controlled destinationDo not require a specific 407 response; probe resistance may disguise rejection
Copy config; use a separately controlled hostname resolving to the server but absent from its certificateTLS identity check failsRestore correct name; never disable certificate verification
Restart only naive-caddy, then make a new requestNew authorized request works after restartInspect persistent state, service identity, and permissions

For the unauthenticated case, use curl --noproxy '' --proxy https://proxy.example.com:443 https://check.example.net/health without credentials. Require proof that the controlled destination was not reached through a tunnel; a reachable public cover page is irrelevant.

In the configured browser, open the IP address tool and compare with your expected server egress. This checks that browser request only. It does not certify UDP, IPv6, all DNS, or every application. Restore a clean configuration after every negative test, then repeat the positive check.

How should NaiveProxy certificate renewal and updates work?

Caddy automates issuance and renewal, provided DNS, challenge access, storage, and CA availability remain usable. Record certificate expiry and monitor service errors. Restarting a service with an already valid certificate is not a renewal test.[5]

Keep staging separate

For an ACME exercise, use a separate hostname, service port arrangement, account, and storage directory. Configure the staging ACME endpoint through Caddy's acme_ca option. On an isolated Ubuntu client, obtain the designated staging CA certificates from the CA's official source and point SSL_CERT_FILE at that explicit trust bundle for the Naive process. Keep hostname verification enabled. Do not install staging roots system-wide or mix this storage with production.[6][7]

First record staging issuance. Demonstrating renewal requires a later replacement certificate and corresponding renewal evidence; if you have only the first certificate, record renewal as unverified. Do not delete production certificate storage or repeatedly force issuance to manufacture a result.

Before an update, preserve the known-working binary, private configuration, unit, and certificate state in an administrator-only backup. Review both projects' releases and security notices: Chromium updates are part of the client maintenance burden. Stage a new version in another directory, validate configuration, update only this unit's executable path, and repeat positive, negative, and restart checks. A rollback restores the previous path and compatible configuration; it is temporary recovery, not permission to retain a vulnerable version indefinitely.

Revoke access and remove the service

Replace or remove the relevant basic_auth credential, validate, and reload this unit. Stop and restart it if you must terminate already-established tunnels, accepting the interruption to other users. An old credential must fail on a fresh connection while the replacement works. For complete shutdown, restore client proxy settings, stop the client, disable and stop naive-caddy, and remove only its firewall rules. Retain private recovery material until rollback is unnecessary, then securely retire credentials and unused DNS records.

Summary

Keep the compatible server, certificate state, and client configuration as separate maintenance boundaries. Accept this route only after authorized requests work, negative cases fail, and restart and revocation behave as intended. The procedure above supplies verification methods; it does not claim that an author-run deployment passed them.

FAQ

Can I use a normal Caddy package?

Use the Naive-compatible prebuilt release for this route. A standard package does not establish the required forward-proxy module and padding compatibility.

Does a successful TLS handshake prove authentication?

No. Verify a request through the authenticated client and repeat it with incorrect credentials, using a controlled destination to detect accidental bypass.

Why keep the client on loopback?

An unauthenticated local SOCKS listener exposed to other machines could let them use your remote credentials. Loopback limits that exposure to the client host.

Must unauthenticated CONNECT return HTTP 407?

No. Probe resistance can conceal the authentication boundary. The important check is that an unauthenticated request cannot obtain authorized forwarding.

Can I disable TLS checking for staging?

Keep validation enabled and explicitly trust the designated staging CA only in the isolated client process. Remove that test trust when the exercise ends.

Is restarting Caddy a renewal test?

No. A restart may reuse the same certificate. Renewal needs evidence of certificate replacement through the renewal lifecycle, not simply successful startup.

Does changing the password disconnect existing tunnels?

Do not assume it does. Terminate established connections when immediate revocation is required, then check that fresh connections using old credentials fail.

Sources:

  1. NaiveProxy client release v154.0.8037.49-4 — https://github.com/klzgrad/naiveproxy/releases/tag/v154.0.8037.49-4
  2. Naive Caddy release v2.11.7-naive — https://github.com/klzgrad/forwardproxy/releases/tag/v2.11.7-naive
  3. Caddy: running as a service — https://caddyserver.com/docs/running
  4. NaiveProxy: server and client configuration — https://github.com/klzgrad/naiveproxy
  5. Caddy: automatic HTTPS — https://caddyserver.com/docs/automatic-https
  6. Caddyfile: global options — https://caddyserver.com/docs/caddyfile/options
  7. Let's Encrypt: staging environment — https://letsencrypt.org/docs/staging-environment/

Sources checked 11 October 2026.

Related Articles:

Start your 3-day free trial

Sign up to experience all premium features at no cost.

*Available only to new users. Each user is limited to one trial.

NaiveProxy Caddy Setup: Authentication and Updates | AethoVPN