From 2c3fb1aa38c821766d7a7f991b078eee526513e9 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Sun, 19 Nov 2023 01:14:12 -0500 Subject: [PATCH] Improve proxy examples, and common patterns --- .../caddyfile/directives/reverse_proxy.md | 63 +++++++++++++++---- src/docs/markdown/caddyfile/patterns.md | 24 +++++-- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/docs/markdown/caddyfile/directives/reverse_proxy.md b/src/docs/markdown/caddyfile/directives/reverse_proxy.md index 5a223bc..ab30fbe 100644 --- a/src/docs/markdown/caddyfile/directives/reverse_proxy.md +++ b/src/docs/markdown/caddyfile/directives/reverse_proxy.md @@ -456,7 +456,7 @@ Additionally, when using the [`http` transport](#the-http-transport), the `Accep #### HTTPS -Since (most) headers retain their original value when being proxied, it is often necessary to override the `Host` header with the configured upstream address when proxying to HTTPS, such that the `Host` header matches the TLS ServerName value. For example: +Since (most) headers retain their original value when being proxied, it is often necessary to override the `Host` header with the configured upstream address when proxying to HTTPS, such that the `Host` header matches the TLS ServerName value: ```caddy-d reverse_proxy https://example.com { @@ -464,6 +464,8 @@ reverse_proxy https://example.com { } ``` +The `X-Forwarded-Host` header is still passed [by default](#defaults), so the upstream may still use that if it needs to know the original `Host` header value. + ### Rewrites @@ -656,7 +658,7 @@ status By HTTP status code. -- **<code...>** is a list of HTTP status codes. Special cases are `2xx`, `3xx`, ... which match against all status codes in the range of 200-299, 300-399, ... respectively +- **<code...>** is a list of HTTP status codes. Special cases are strings like `2xx` and `3xx`, which match against all status codes in the range of `200`-`299` and `300`-`399`, respectively. ##### header @@ -675,23 +677,33 @@ reverse_proxy localhost:9005 ``` -Load-balance all requests between 3 backends: +[Load-balance](#load-balancing) all requests [between 3 backends](#upstreams): ```caddy-d reverse_proxy node1:80 node2:80 node3:80 ``` -Same, but only requests within `/api`, and with header affinity: +Same, but only requests within `/api`, and sticky by using the [`cookie` policy](#lb_policy): ```caddy-d reverse_proxy /api/* node1:80 node2:80 node3:80 { - lb_policy header X-My-Header + lb_policy cookie api_sticky } ``` -Configure some transport options: +Using [active health checks](#active-health-checks) to determine which backends are healthy, and enabling [retries](#lb_try_duration) on failed connections, holding the request until a healthy backend is found: + +```caddy-d +reverse_proxy node1:80 node2:80 node3:80 { + health_uri /healthz + lb_try_duration 5s +} +``` + + +Configure some [transport options](#transports): ```caddy-d reverse_proxy localhost:8080 { @@ -703,7 +715,7 @@ reverse_proxy localhost:8080 { ``` -Reverse proxy to an HTTPS endpoint: +Reverse proxy to an [HTTPS upstream](#https): ```caddy-d reverse_proxy https://example.com { @@ -712,7 +724,30 @@ reverse_proxy https://example.com { ``` -Strip a path prefix before proxying: +Reverse proxy to an HTTPS upstream, but [⚠️ disable TLS verification](#tls_insecure_skip_verify). this is NOT RECOMMENDED, since it disables all security checks that HTTPS offers; proxying over over HTTP in private networks is preferred if possible, because it avoids the false sense of security: + +```caddy-d +reverse_proxy 10.0.0.1:443 { + transport http { + tls_insecure_skip_verify + } +} +``` + + +Instead you may establish trust with the upstream by explicitly [trusting the upstream's certificate](#tls_trusted_ca_certs): + +```caddy-d +reverse_proxy 10.0.0.1:443 { + transport http { + tls_trusted_ca_certs /path/to/cert.pem + } +} +``` + + + +[Strip a path prefix](/docs/caddyfile/directives/handle_path) before proxying; but be aware of the [subfolder problem ](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575): ```caddy-d handle_path /prefix/* { @@ -721,7 +756,7 @@ handle_path /prefix/* { ``` -Replace a path prefix before proxying: +Replace a path prefix before proxying, using a [rewrite](/docs/caddyfile/directives/rewrite): ```caddy-d handle_path /old-prefix/* { @@ -731,7 +766,7 @@ handle_path /old-prefix/* { ``` -`X-Accel-Redirect` support, i.e. serving static files as requested by the proxy upstream: +`X-Accel-Redirect` support, i.e. serving static files as requested, by [intercepting the response](#intercepting-responses): ```caddy-d reverse_proxy localhost:8080 { @@ -746,7 +781,7 @@ reverse_proxy localhost:8080 { ``` -Custom error page for errors from upstream: +Custom error page for errors from upstream, by [intercepting error responses](#intercepting-responses) by status code: ```caddy-d reverse_proxy localhost:8080 { @@ -760,7 +795,7 @@ reverse_proxy localhost:8080 { ``` -Get backends dynamically from `A`/`AAAA` record DNS queries: +Get backends [dynamically](#dynamic-upstreams) from [`A`/`AAAA` record](#aaaaa) DNS queries: ```caddy-d reverse_proxy { @@ -769,10 +804,12 @@ reverse_proxy { ``` -Get backends dynamically from `SRV` record DNS queries: +Get backends [dynamically](#dynamic-upstreams) from [`SRV` record](#srv) DNS queries: ```caddy-d reverse_proxy { dynamic srv _api._tcp.example.com } ``` + + diff --git a/src/docs/markdown/caddyfile/patterns.md b/src/docs/markdown/caddyfile/patterns.md index 12374d6..b4e1653 100644 --- a/src/docs/markdown/caddyfile/patterns.md +++ b/src/docs/markdown/caddyfile/patterns.md @@ -29,6 +29,7 @@ example.com { As usual, the first line is the site address. The [`root` directive](/docs/caddyfile/directives/root) specifies the path to the root of the site (the `*` means to match all requests, so as to disambiguate from a [path matcher](/docs/caddyfile/matchers#path-matchers))—change the path to your site if it isn't the current working directory. Finally, we enable the [static file server](/docs/caddyfile/directives/file_server). + ## Reverse proxy Proxy all requests: @@ -49,6 +50,11 @@ example.com { } ``` +This uses a [request matcher](/docs/caddyfile/matchers#syntax) to match only requests that start with `/api/` and proxy them to the backend. All other requests will be served from the site [`root`](/docs/caddyfile/directives/root) with the [static file server](/docs/caddyfile/directives/file_server). This also depends on the fact that `reverse_proxy` is higher on the [directive order](/docs/caddyfile/directives#directive-order) than `file_server`. + +There are many more [`reverse_proxy` examples here](/docs/caddyfile/directives/reverse_proxy#examples). + + ## PHP @@ -63,11 +69,18 @@ example.com { } ``` -Customize the site root accordingly; this example assumes that your PHP app's webroot is within a `public` directory—requests for files that exist on disk will be served with `file_server`, and anything else will be routed to `index.php` for handling by the PHP app. +Customize the site root accordingly; this example assumes that your PHP app's webroot is within a `public` directory—requests for files that exist on disk will be served with [`file_server`](/docs/caddyfile/directives/file_server), and anything else will be routed to `index.php` for handling by the PHP app. + +You may sometimes use a unix socket to connect to PHP-FPM: + +```caddy-d +php_fastcgi unix//run/php/php8.2-fpm.sock +``` The [`php_fastcgi` directive](/docs/caddyfile/directives/php_fastcgi) is actually just a shortcut for [several pieces of configuration](/docs/caddyfile/directives/php_fastcgi#expanded-form). + ## Redirect `www.` subdomain To **add** the `www.` subdomain with an HTTP redirect: @@ -94,7 +107,7 @@ example.com { ``` -To remove it for **multiple domains** at once; this uses the `{labels.*}` placeholders which are the parts of the hostname, 0-indexed from the right (e.g. 0=com, 1=example-one, 2=www): +To remove it for **multiple domains** at once; this uses the `{labels.*}` placeholders which are the parts of the hostname, `0`-indexed from the right (e.g. `0`=`com`, `1`=`example-one`, `2`=`www`): ```caddy www.example-one.com, www.example-two.com { @@ -106,6 +119,7 @@ example-one.com, example-two.com { ``` + ## Trailing slashes You will not usually need to configure this yourself; the [`file_server` directive](/docs/caddyfile/directives/file_server) will automatically add or remove trailing slashes from requests by way of HTTP redirects, depending on whether the requested resource is a directory or file, respectively. @@ -143,7 +157,7 @@ Using a redirect, the client will have to re-issue the request, enforcing a sing ## Wildcard certificates -If you need to serve multiple subdomains with the same wildcard certificate, the best way to handle them is with a Caddyfile like this, making use of the [`handle`](/docs/caddyfile/directives/handle) directive and [`host`](/docs/caddyfile/matchers#host) matchers: +If you need to serve multiple subdomains with the same wildcard certificate, the best way to handle them is with a Caddyfile like this, making use of the [`handle` directive](/docs/caddyfile/directives/handle) and [`host` matchers](/docs/caddyfile/matchers#host): ```caddy *.example.com { @@ -168,7 +182,7 @@ If you need to serve multiple subdomains with the same wildcard certificate, the } ``` -Note that you must enable the [ACME DNS challenge](/docs/automatic-https#dns-challenge) to have Caddy automatically manage wildcard certificates. +You must enable the [ACME DNS challenge](/docs/automatic-https#dns-challenge) to have Caddy automatically manage wildcard certificates. @@ -176,7 +190,7 @@ Note that you must enable the [ACME DNS challenge](/docs/automatic-https#dns-cha When a web page does its own routing, servers may receive lots of requests for pages that don't exist server-side, but which are renderable client-side as long as the singular index file is served instead. Web applications architected like this are known as SPAs, or single-page apps. -The main idea is to have the server "try files" to see if the requested file exists server-side, and if not, fall back to an index file where the client does the routing (usually with client-side JavaScript): `try_files {path} /index.html` +The main idea is to have the server "try files" to see if the requested file exists server-side, and if not, fall back to an index file where the client does the routing (usually with client-side JavaScript). A typical SPA config usually looks something like this: