Skip to content

Commit 8383561

Browse files
Copilotskjnldsv
authored andcommitted
docs: add Caddy web server configuration and sample Caddyfile
Revives and fixes #9199, adding a complete Caddy 2.6+ + PHP-FPM configuration sample and documentation page for Nextcloud. New files: - Caddyfile.sample: complete working config covering compression, security headers, .well-known routing, asset caching, internal path blocking, and PHP-FPM passthrough - caddy.rst: documentation page modelled after nginx.rst Fixes from original PR review: - Fix typo /corn.php -> /cron.php - Use :language: nginx (no caddyfile Pygments lexer available) - Fix "webroot of your nginx installation" -> "Caddy installation" - Expand subdir section with handle_path + REQUEST_URI workaround - Add OVERWRITEWEBROOT note for subdirectory deployments - Add FrankenPHP note with php_server alternative - Add .. _caddy-config: ref label for cross-referencing - Use 127.0.0.1:9000 as default PHP-FPM address with comment to adjust caddy added to installation/index.rst toctree after nginx. Signed-off-by: skjnldsv <skjnldsv@protonmail.com> Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
1 parent 00e2e61 commit 8383561

3 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
cloud.example.com # Public server hostname
2+
3+
request_body {
4+
max_size 10G
5+
}
6+
7+
# Enable compression but do not remove ETag headers
8+
encode {
9+
zstd
10+
gzip 4
11+
12+
minimum_length 256
13+
14+
match {
15+
header Content-Type application/atom+xml
16+
header Content-Type application/javascript
17+
header Content-Type application/json
18+
header Content-Type application/ld+json
19+
header Content-Type application/manifest+json
20+
header Content-Type application/rss+xml
21+
header Content-Type application/vnd.geo+json
22+
header Content-Type application/vnd.ms-fontobject
23+
header Content-Type application/wasm
24+
header Content-Type application/x-font-ttf
25+
header Content-Type application/x-web-app-manifest+json
26+
header Content-Type application/xhtml+xml
27+
header Content-Type application/xml
28+
header Content-Type font/opentype
29+
header Content-Type image/bmp
30+
header Content-Type image/svg+xml
31+
header Content-Type image/x-icon
32+
header Content-Type text/cache-manifest
33+
header Content-Type text/css
34+
header Content-Type text/plain
35+
header Content-Type text/vcard
36+
header Content-Type text/vnd.rim.location.xloc
37+
header Content-Type text/vtt
38+
header Content-Type text/x-component
39+
header Content-Type text/x-cross-domain-policy
40+
}
41+
}
42+
43+
# Add security-related headers
44+
header {
45+
Referrer-Policy no-referrer
46+
Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"
47+
X-Content-Type-Options nosniff
48+
X-Download-Options noopen
49+
X-Frame-Options SAMEORIGIN
50+
X-Permitted-Cross-Domain-Policies none
51+
X-Robots-Tag "noindex, nofollow"
52+
X-XSS-Protection "1; mode=block"
53+
# Remove X-Powered-By header (already removed by default in newer Caddy)
54+
-X-Powered-By
55+
}
56+
57+
# Path to the root of your installation
58+
root * /var/www/nextcloud
59+
60+
route {
61+
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
62+
@msftdavclient {
63+
header User-Agent DavClnt*
64+
path /
65+
}
66+
redir @msftdavclient /remote.php/webdav/ temporary
67+
68+
route /robots.txt {
69+
skip_log
70+
file_server
71+
}
72+
73+
# Add exception for `/.well-known` so that clients can still access it
74+
# despite the existence of the `error @internal 404` rule which would
75+
# otherwise handle requests for `/.well-known` below
76+
route /.well-known/* {
77+
redir /.well-known/carddav /remote.php/dav/ permanent
78+
redir /.well-known/caldav /remote.php/dav/ permanent
79+
80+
@well-known-static path \
81+
/.well-known/acme-challenge /.well-known/acme-challenge/* \
82+
/.well-known/pki-validation /.well-known/pki-validation/*
83+
route @well-known-static {
84+
try_files {path} {path}/ =404
85+
file_server
86+
}
87+
88+
redir * /index.php{path} permanent
89+
}
90+
91+
# Block access to internal/sensitive paths
92+
@internal path \
93+
/build /build/* \
94+
/tests /tests/* \
95+
/config /config/* \
96+
/lib /lib/* \
97+
/3rdparty /3rdparty/* \
98+
/templates /templates/* \
99+
/data /data/* \
100+
\
101+
/.* \
102+
/autotest* \
103+
/occ* \
104+
/issue* \
105+
/indie* \
106+
/db_* \
107+
/console*
108+
error @internal 404
109+
110+
@assets {
111+
path *.css *.js *.svg *.gif *.png *.jpg *.jpeg *.ico *.wasm *.tflite *.map *.wasm2
112+
file {path} # Only if requested file exists on disk, otherwise /index.php will handle it
113+
}
114+
route @assets {
115+
header Cache-Control "max-age=15552000" # Cache-Control policy borrowed from `.htaccess`
116+
# Note: to give .woff2 files a shorter TTL, add a nested route for *.woff2
117+
# with `header Cache-Control "max-age=604800"` before this one.
118+
skip_log # Optional: Don't log access to assets
119+
file_server {
120+
precompressed gzip
121+
}
122+
}
123+
124+
# Rule borrowed from `.htaccess`
125+
redir /remote/* /remote.php{path} permanent
126+
127+
# Serve found static files, falling through to PHP handler if not found
128+
try_files {path} {path}/
129+
@notphpordir not path /*.php /*.php/* / /*/
130+
file_server @notphpordir {
131+
pass_thru
132+
}
133+
134+
# Required for legacy support
135+
#
136+
# Rewrites all other requests to be prepended with "/index.php" unless they already
137+
# match a known PHP entry point.
138+
@unknownphppath not path \
139+
/index.php /index.php/* \
140+
/remote.php /remote.php/* \
141+
/public.php /public.php/* \
142+
/cron.php /cron.php/* \
143+
/core/ajax/update.php /core/ajax/update.php/* \
144+
/status.php /status.php/* \
145+
/ocs/v1.php /ocs/v1.php/* \
146+
/ocs/v2.php /ocs/v2.php/* \
147+
/updater/*.php /updater/*.php/* \
148+
/ocm-provider/*.php /ocm-provider/*.php/* \
149+
/ocs-provider/*.php /ocs-provider/*.php/*
150+
rewrite @unknownphppath /index.php{path}
151+
152+
# Let everything else be handled by the PHP-FPM component
153+
# Adjust the address to match your PHP-FPM socket or TCP address
154+
# (e.g. unix//var/run/php/php-fpm.sock or 127.0.0.1:9000)
155+
php_fastcgi 127.0.0.1:9000 {
156+
env modHeadersAvailable true # Avoid sending the security headers twice
157+
env front_controller_active true # Enable pretty urls
158+
}
159+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
.. _caddy-config:
2+
3+
===================
4+
Caddy configuration
5+
===================
6+
7+
.. warning::
8+
Please note that webservers other than Apache 2.x are not officially supported.
9+
10+
.. note::
11+
This page covers example Caddy configuration to run a Nextcloud server.
12+
These configuration examples were originally provided by
13+
`@ntninja <https://github.com/ntninja>`_ based on the :doc:`nginx` sample and
14+
are exclusively community-maintained. (Thank you contributors!)
15+
16+
- This guide assumes you are using Caddy 2.6 or later and the presented sample
17+
configuration will not work on older versions without modification.
18+
- Caddy takes care of TLS certificate configuration and HTTP-to-HTTPS redirects
19+
automatically, so that is not covered here.
20+
- The example configuration makes use of the `route <https://caddyserver.com/docs/caddyfile/directives/route>`_
21+
directive which disables all directive reordering usually done by Caddy. This
22+
means that anything within that block should be read strictly top-to-bottom
23+
unlike what you may be used to from NGINX or regular (non-route) Caddy
24+
configurations.
25+
- Be careful about line breaks if you copy the examples, as long lines may be
26+
broken for page formatting.
27+
- Some environments might need a ``cgi.fix_pathinfo`` set to ``1`` in their
28+
``php.ini``.
29+
30+
.. note::
31+
If you are using **FrankenPHP** (an application server built on top of Caddy),
32+
you can use the ``php_server`` directive instead of the ``php_fastcgi``-based
33+
approach described on this page. FrankenPHP handles the try-files logic and PHP
34+
routing internally, which greatly simplifies the configuration. See the
35+
`FrankenPHP documentation <https://frankenphp.dev/docs/>`_ and a community
36+
example at https://gitlab.com/greyxor/nextcloud-docker for reference.
37+
38+
Nextcloud in the webroot of Caddy
39+
----------------------------------
40+
41+
The following configuration should be used when Nextcloud is placed in the
42+
webroot of your Caddy installation. In this example it is
43+
``/var/www/nextcloud`` and it is accessed via ``http(s)://cloud.example.com/``
44+
45+
.. literalinclude:: Caddyfile.sample
46+
:language: nginx
47+
48+
Nextcloud in a subdir of the Caddy webroot
49+
------------------------------------------
50+
51+
Serving Nextcloud from a subdirectory (e.g. ``https://cloud.example.com/nextcloud/``)
52+
requires extra steps with Caddy compared to NGINX, due to the way Caddy's
53+
``handle_path`` strips the prefix from ``PATH_INFO`` but not from ``REQUEST_URI``,
54+
while Nextcloud relies on ``REQUEST_URI``.
55+
56+
The recommended approach is:
57+
58+
1. Set ``'overwritewebroot' => '/nextcloud'`` in your Nextcloud ``config/config.php``.
59+
2. Wrap the main Caddyfile configuration in a ``handle_path /nextcloud/* { … }`` block,
60+
or use ``uri strip_prefix /nextcloud``.
61+
3. Capture the rewritten URI before the PHP handler and pass it as ``REQUEST_URI``:
62+
63+
.. code-block:: nginx
64+
65+
handle_path /nextcloud/* {
66+
# … (place the route block contents here) …
67+
68+
vars rewritten_uri {uri}
69+
70+
# Let everything else be handled by the PHP-FPM component
71+
php_fastcgi app:9000 {
72+
env modHeadersAvailable true
73+
env front_controller_active true
74+
env REQUEST_URI {vars.rewritten_uri}
75+
}
76+
}
77+
78+
.. note::
79+
With FrankenPHP's ``php_server`` directive and the
80+
``htaccess.IgnoreFrontController`` option, subdirectory support is handled
81+
automatically without these workarounds.
82+
83+
Tips and tricks
84+
---------------
85+
86+
Suppressing log messages
87+
^^^^^^^^^^^^^^^^^^^^^^^^
88+
89+
If you're seeing meaningless messages in your logfile, for example ``client
90+
denied by server configuration: /var/www/data/htaccesstest.txt``, add this
91+
section to your Caddy configuration to suppress them:
92+
93+
.. code-block:: nginx
94+
95+
route {
96+
# …
97+
98+
route /data/htaccesstest.txt {
99+
skip_log # Silences logging for the matched path
100+
file_server
101+
}
102+
103+
# …
104+
}

admin_manual/installation/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Installation and server configuration
1414
automatic_configuration
1515
selinux_configuration
1616
nginx
17+
caddy
1718
harden_server
1819
server_tuning
1920

0 commit comments

Comments
 (0)