Caddy
Caddy is the recommended starting point when you do not already run a reverse proxy. Its normal public-hostname flow obtains and renews certificates automatically, and Jiandu needs only a short Caddyfile.
This guide assumes:
- users open
https://documents.example.net; - Caddy can reach Jiandu at
jiandu:8077; and - Jiandu sees Caddy's direct connection from
172.30.0.2.
Replace all three values for your deployment. The trusted address must be the address Jiandu actually observes, not merely the address in this example.
1. Configure Jiandu
{
"schema_version": 1,
"server": {
"bind": "0.0.0.0:8077",
"request_timeout_seconds": 30,
"ingress": {
"mode": "https_reverse_proxy",
"public_origin": "https://documents.example.net",
"trusted_proxy_cidrs": ["172.30.0.2/32"]
}
}
}
For two host processes, replace the bind address with 127.0.0.1:8077 and the trusted CIDR with
127.0.0.1/32. In a container network, pinning Caddy to a dedicated /32 prevents an unrelated
container on the same subnet from becoming a trusted proxy.
2. Add the Caddy route
documents.example.net {
header Strict-Transport-Security "max-age=31536000"
reverse_proxy jiandu:8077 {
header_up Host {http.request.host}
header_up X-Forwarded-Proto https
header_up X-Forwarded-For {http.request.remote.host}
header_up -X-Jiandu-Proxy-Secret
header_up -X-Auth-Subject
header_up -X-Auth-Name
header_up -X-Auth-Groups
}
}
Do not add tls internal for a public hostname. With DNS pointing to Caddy and ports 80/443
reachable as required by the selected ACME challenge, Caddy's default automation obtains a public
certificate. See Caddy's automatic HTTPS requirements.
For a private lab where every client can trust your private CA, add:
tls internal
Export and install the Caddy root CA on each test client. Clicking through a browser warning does not establish a sound production boundary.
Why each directive is present
| Directive | Purpose |
|---|---|
documents.example.net | Selects the only host this site block serves and activates HTTPS certificate management. It must equal Jiandu's public_origin host. |
header Strict-Transport-Security ... | Tells browsers to return over HTTPS for one year. It intentionally omits subdomains and preload. |
reverse_proxy jiandu:8077 | Sends traffic to the private Jiandu listener. This address must not be publicly routable. |
header_up Host ... | Preserves the external host and any non-default port so Jiandu can compare it with public_origin. |
header_up X-Forwarded-Proto https | Replaces any client value with the scheme established by this TLS edge. |
header_up X-Forwarded-For ... | Replaces, rather than appends to, browser-controlled forwarding data. Jiandu can then apply client-aware rate limits behind the trusted hop. |
header_up -X-... | Deletes identity assertions and proxy secrets supplied by an untrusted client. Extend this list if trusted-proxy authentication uses different header names. |
Caddy's reverse proxy supports streaming bodies without a whole-request buffering directive. Do
not add a short response_header_timeout or request-body limit unless you have sized it for slow
uploads, downloads, and Jiandu's resumable upload requests. Caddy's
reverse_proxy reference describes
the transport controls if your network requires explicit timeouts.
3. Isolate the backend network
In Compose, publish only Caddy and keep the backend internal:
services:
jiandu:
expose:
- "8077"
networks:
backend:
ipv4_address: 172.30.0.10
caddy:
image: caddy:2.10.2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
networks:
edge: {}
backend:
ipv4_address: 172.30.0.2
networks:
edge: {}
backend:
internal: true
ipam:
config:
- subnet: 172.30.0.0/24
volumes:
caddy-data: {}
caddy-config: {}
Persist both Caddy volumes: /data contains certificate state and /config contains runtime
configuration. Do not publish Jiandu's port with ports:. The repository's
examples/docker-compose
directory contains the complete runnable topology.
4. Validate the boundary
caddy validate --config /etc/caddy/Caddyfile
curl --fail --silent https://documents.example.net/api/v1/health/ready
curl --silent --show-error --head https://documents.example.net/ | grep -i strict-transport-security
Also confirm that http://<server>:8077 is unreachable from another machine. If Jiandu returns
421 ingress_not_allowed, inspect the Caddy address on the backend network and update the /32;
do not widen it to the entire private address space as a shortcut.