Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions admin_manual/installation/Caddyfile.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
cloud.example.com # Public server hostname

request_body {
max_size 10G
}

# Enable compression but do not remove ETag headers
encode {
zstd
gzip 4

minimum_length 256

match {
header Content-Type application/atom+xml
header Content-Type application/javascript
header Content-Type application/json
header Content-Type application/ld+json
header Content-Type application/manifest+json
header Content-Type application/rss+xml
header Content-Type application/vnd.geo+json
header Content-Type application/vnd.ms-fontobject
header Content-Type application/wasm
header Content-Type application/x-font-ttf
header Content-Type application/x-web-app-manifest+json
header Content-Type application/xhtml+xml
header Content-Type application/xml
header Content-Type font/opentype
header Content-Type image/bmp
header Content-Type image/svg+xml
header Content-Type image/x-icon
header Content-Type text/cache-manifest
header Content-Type text/css
header Content-Type text/plain
header Content-Type text/vcard
header Content-Type text/vnd.rim.location.xloc
header Content-Type text/vtt
header Content-Type text/x-component
header Content-Type text/x-cross-domain-policy
}
}

# Add security-related headers
header {
Referrer-Policy no-referrer
Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"
X-Content-Type-Options nosniff
X-Download-Options noopen
X-Frame-Options SAMEORIGIN
X-Permitted-Cross-Domain-Policies none
X-Robots-Tag "noindex, nofollow"
X-XSS-Protection "1; mode=block"
# Remove X-Powered-By header (already removed by default in newer Caddy)
-X-Powered-By
}

# Path to the root of your installation
root * /var/www/nextcloud

route {
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
@msftdavclient {
header User-Agent DavClnt*
path /
}
redir @msftdavclient /remote.php/webdav/ temporary

route /robots.txt {
skip_log
file_server
}

# Add exception for `/.well-known` so that clients can still access it
# despite the existence of the `error @internal 404` rule which would
# otherwise handle requests for `/.well-known` below
route /.well-known/* {
redir /.well-known/carddav /remote.php/dav/ permanent
redir /.well-known/caldav /remote.php/dav/ permanent

@well-known-static path \
/.well-known/acme-challenge /.well-known/acme-challenge/* \
/.well-known/pki-validation /.well-known/pki-validation/*
route @well-known-static {
try_files {path} {path}/ =404
file_server
}

redir * /index.php{path} permanent
}

# Block access to internal/sensitive paths
@internal path \
/build /build/* \
/tests /tests/* \
/config /config/* \
/lib /lib/* \
/3rdparty /3rdparty/* \
/templates /templates/* \
/data /data/* \
\
/.* \
/autotest* \
/occ* \
/issue* \
/indie* \
/db_* \
/console*
error @internal 404

@assets {
path *.css *.js *.svg *.gif *.png *.jpg *.jpeg *.ico *.wasm *.tflite *.map *.wasm2
file {path} # Only if requested file exists on disk, otherwise /index.php will handle it
}
route @assets {
header Cache-Control "max-age=15552000" # Cache-Control policy borrowed from `.htaccess`
# Note: to give .woff2 files a shorter TTL, add a nested route for *.woff2
# with `header Cache-Control "max-age=604800"` before this one.
skip_log # Optional: Don't log access to assets
file_server {
precompressed gzip
}
}

# Rule borrowed from `.htaccess`
redir /remote/* /remote.php{path} permanent

# Serve found static files, falling through to PHP handler if not found
try_files {path} {path}/
@notphpordir not path /*.php /*.php/* / /*/
file_server @notphpordir {
pass_thru
}

# Required for legacy support
#
# Rewrites all other requests to be prepended with "/index.php" unless they already
# match a known PHP entry point.
@unknownphppath not path \
/index.php /index.php/* \
/remote.php /remote.php/* \
/public.php /public.php/* \
/cron.php /cron.php/* \
/core/ajax/update.php /core/ajax/update.php/* \
/status.php /status.php/* \
/ocs/v1.php /ocs/v1.php/* \
/ocs/v2.php /ocs/v2.php/* \
/updater/*.php /updater/*.php/* \
/ocm-provider/*.php /ocm-provider/*.php/* \
/ocs-provider/*.php /ocs-provider/*.php/*
rewrite @unknownphppath /index.php{path}

# Let everything else be handled by the PHP-FPM component
php_fastcgi nextcloud:9000 {
env modHeadersAvailable true # Avoid sending the security headers twice
env front_controller_active true # Enable pretty urls
}
}
102 changes: 102 additions & 0 deletions admin_manual/installation/caddy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
===================
Caddy configuration
===================

.. warning::
Please note that webservers other than Apache 2.x are not officially supported.

.. note::
This page covers example Caddy configuration to run a Nextcloud server.
These configuration examples were originally provided by
`@ntninja <https://github.com/ntninja>`_ based on the :doc:`nginx` sample and
are exclusively community-maintained. (Thank you contributors!)

- This guide assumes you are using Caddy 2.6 or later and the presented sample
configuration will not work on older versions without modification.
- Caddy takes care of TLS certificate configuration and HTTP-to-HTTPS redirects
automatically, so that is not covered here.
- The example configuration makes use of the `route <https://caddyserver.com/docs/caddyfile/directives/route>`_
directive which disables all directive reordering usually done by Caddy. This
means that anything within that block should be read strictly top-to-bottom
unlike what you may be used to from NGINX or regular (non-route) Caddy
configurations.
- Be careful about line breaks if you copy the examples, as long lines may be
broken for page formatting.
- Some environments might need a ``cgi.fix_pathinfo`` set to ``1`` in their
``php.ini``.

.. note::
If you are using **FrankenPHP** (an application server built on top of Caddy),
you can use the ``php_server`` directive instead of the ``php_fastcgi``-based
approach described on this page. FrankenPHP handles the try-files logic and PHP
routing internally, which greatly simplifies the configuration. See the
`FrankenPHP documentation <https://frankenphp.dev/docs/>`_ and a community
example at https://gitlab.com/greyxor/nextcloud-docker for reference.

Nextcloud in the webroot of Caddy
----------------------------------

The following configuration should be used when Nextcloud is placed in the
webroot of your Caddy installation. In this example it is
``/var/www/nextcloud`` and it is accessed via ``http(s)://cloud.example.com/``

.. literalinclude:: Caddyfile.sample
:language: nginx

Nextcloud in a subdir of the Caddy webroot
------------------------------------------

Serving Nextcloud from a subdirectory (e.g. ``https://cloud.example.com/nextcloud/``)
requires extra steps with Caddy compared to NGINX, due to the way Caddy's
``handle_path`` strips the prefix from ``PATH_INFO`` but not from ``REQUEST_URI``,
while Nextcloud relies on ``REQUEST_URI``.

The recommended approach is:

1. Set ``'overwritewebroot' => '/nextcloud'`` in your Nextcloud ``config/config.php``.
2. Wrap the main Caddyfile configuration in a ``handle_path /nextcloud/* { … }`` block,
or use ``uri strip_prefix /nextcloud``.
3. Capture the rewritten URI before the PHP handler and pass it as ``REQUEST_URI``:

.. code-block:: nginx

handle_path /nextcloud/* {
# … (place the route block contents here) …

vars rewritten_uri {uri}

# Let everything else be handled by the PHP-FPM component
php_fastcgi app:9000 {
env modHeadersAvailable true
env front_controller_active true
env REQUEST_URI {vars.rewritten_uri}
}
}

.. note::
With FrankenPHP's ``php_server`` directive and the
``htaccess.IgnoreFrontController`` option, subdirectory support is handled
automatically without these workarounds.

Tips and tricks
---------------

Suppressing log messages
^^^^^^^^^^^^^^^^^^^^^^^^

If you're seeing meaningless messages in your logfile, for example ``client
denied by server configuration: /var/www/data/htaccesstest.txt``, add this
section to your Caddy configuration to suppress them:

.. code-block:: nginx

route {
# …

route /data/htaccesstest.txt {
skip_log # Silences logging for the matched path
file_server
}

# …
}
1 change: 1 addition & 0 deletions admin_manual/installation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Installation and server configuration
automatic_configuration
selinux_configuration
nginx
caddy
harden_server
server_tuning

Expand Down
Loading