Nextcloud on Podman behind Bunker Nginx server (version 1.2.7 and higher) - joefidler/joefidler.github.io GitHub Wiki
This setup up uses Podman (rootless) to run a containerized Nextcloud with a secured "Bunkerized" version of the Nginx webserver in front. I have tested this against Bunkerity Nginx version 1.2.7. both via the web and a bunch of file and CALDav clients. This is an updated version with significant changes compared to the previous version tested against Bunker Nginx 1.2.4. Be warned - I know almost nothing about security! Mostly I am writing this up is for my own use - if others find it helpful that's great.
I have relied heavily on several sources to get this working - as well as a lot debugging and log files:
- https://github.com/bunkerity/bunkerized-nginx/tree/master/examples/nextcloud
- http://docs.podman.io/en/latest/Commands.html
- https://www.underkube.com/posts/2021-01-28-nextcloud-podman-rootless-systemd-part-i-introduction/
Changes to previous version
- Add more whitelisted Nginx user agents (this list will depend on what you use) : iOS gvfs DAVx5 Evolution
- Add REPORT to allowed methods in modsec-crs-confs/nextcloud.conf
- added .welknown stuff to the Nginx server conf to allow iOS & Apple Mac clients easier connection.
- added security these id rules
SecRuleRemoveById 949110
SecRuleRemoveById 920420
SecRequestBodyLimit 100000000 (see not below)
-
Nginx Secure Request Body Limit ( SecRequestBodyLimit) This effects the Nextcloud file client uploads by limiting the max file size that can be uploaded. reference: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#secrequestbodylimit
-
bad behaviours This is a new feature in Bunker Nginx. I have set this to off as many of the bad behaviours listede seem to be normal operation for Nextcloud, so I could not get it to work with this on - especially with WebDAV file clients. reference: https://github.com/bunkerity/bunkerized-nginx/blob/master/docs/security_tuning.md#bad-behaviors-detection
Network Ports
The following ports need to be opened in the firewall and redirected to this server. See my post here for suggestions on on how to do this.
80 -> 8080
443 -> 8443
Create storage volumes
mkdir -p ~/containers/nextcloud/{db,nginx,html}
mkdir -p ~/containers/nextcloud/nginx/{certs,html,modsec-confs,modsec-crs-confs,server-confs}
where:
db will host the database
nginx contains the custom nginx conf files and encryption certificates
html will host the Nextcloud content and be the webroot
Set directory permissions for SSL certificate storage
Bunkerized-nginx runs as an unprivileged user with UID/GID 101, therefore we set the rights of ~/containers/nextcloud/certs accordingly. See here for details. So we change the host system permissions so the nginx container user can access the shared files.
podman unshare chown 101:101 ~/containers/nextcloud/nginx/certs
Create Nginx config files
I use CalDAV and WebDAV remote clients with my Nextcloud, so I had to modify the original bunkerized security settings for Nginx to allow these through. Again - I am not a security expert so please use these settings with caution and check with someone who knows what they are doing.
For me a quick way to create these files is to cut/paste into your favorite editor (that's nano for me).
- nano ~/containers/nextcloud/nginx/modsec-confs/nextcloud.conf
SecRuleRemoveById 921110
SecRuleRemoveById 949110
SecRuleRemoveById 920420
SecRequestBodyLimit 100000000
SecRule REQUEST_FILENAME "@contains /remote.php/webdav" "id:1,nolog,pass,ctl:ruleRemoveByTag=OWASP_CRS"
- nano ~/containers/nextcloud/nginx/modsec-crs-confs/nextcloud.conf
SecAction \
"id:900130,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.crs_exclusions_nextcloud=1"
SecAction \
"id:900200,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:'tx.allowed_methods=GET POST HEAD COPY DELETE LOCK MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK REPORT OPTIONS'"
- nano ~/containers/nextcloud/nginx/server-confs/nextcloud.conf
location ~ \.php(?:$|/) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
fastcgi_param front_controller_active true; # Enable pretty urls
fastcgi_pass nextcloud:9000;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ \.(?:css|js|svg|gif)$ {
try_files $uri /index.php$request_uri;
expires 6M; # Cache-Control policy borrowed from `.htaccess`
}
location ~ \.woff2?$ {
try_files $uri /index.php$request_uri;
expires 7d; # Cache-Control policy borrowed from `.htaccess`
}
location / {
try_files $uri /index.php$request_uri;
}
location /.well-known {
# The following 6 rules are borrowed from `.htaccess`
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
# Anything else is dynamically handled by Nextcloud
location ^~ /.well-known { return 301 /index.php$uri; }
try_files $uri $uri/ =404;
}
Create the pod
I called mine "nextcloud_pod".
podman pod create --hostname nextcloud_pod --name nextcloud_pod -p 8080:8080 -p 8443:8443
Create the Mariadb database
podman pull docker.io/library/mariadb:latest
podman run --name mariadb \
--pod nextcloud_pod \
-v ~/containers/nextcloud/db:/var/lib/mysql:Z \
-e MYSQL_USER="nextcloud" \
-e MYSQL_PASSWORD="sql-password" \
-e MYSQL_ROOT_PASSWORD="sql-root-password" \
-e MYSQL_DATABASE="nextcloud" \
-d --restart=always \
docker.io/library/mariadb:latest
Run Nextcloud
podman pull docker.io/library/nextcloud:fpm-alpine
podman run --name nextcloud \
--pod nextcloud_pod \
-v ~/containers/nextcloud/html:/var/www/html:z \
-d --restart=always \
-e MYSQL_HOST="127.0.0.1" \
-e MYSQL_USER="nextcloud" \
-e MYSQL_PASSWORD="sql-password" \
-e MYSQL_DATABASE="nextcloud" \
docker.io/library/nextcloud:fpm-alpine
Check Nextcloud is starting
At this stage you can test Nextcloud, before starting the Nginx server.
podman logs nextcloud_container_id
should show
ready to handle connections
Start the Nginx webserver
The Bunker Nginx server does not rely on Docker sockets (docker.sock) for communication, which are mostly unsupported by Podman. Version 1.2.7 seems to start much quicker and may have better performance generally.
If you need more info on this approach see https://github.com/bunkerity/bunkerized-nginx and https://github.com/bunkerity/bunkerized-nginx/blob/master/examples/nextcloud/docker-compose.yml
- You will need to own a registered domain name so that the encryption certificates can be issued from Let's Encrypt.
podman pull bunkerity/bunkerized-nginx:1.2.7
podman run --name=nginx-bunkerized --pod=nextcloud_pod \
-d --restart=always \
-e SERVER_NAME='your.domain.name' \
-e AUTO_LETS_ENCRYPT=yes \
-e REDIRECT_HTTP_TO_HTTPS=yes \
-e DISABLE_DEFAULT_SERVER=yes \
-e MAX_CLIENT_SIZE=10G \
-e USE_CLIENT_CACHE=yes \
-e REMOTE_PHP=nextcloud \
-e REMOTE_PHP_PATH='/var/www/html' \
-e LIMIT_REQ_RATE='5r/s' \
-e LIMIT_REQ_BURST=10 \
-e ALLOWED_METHODS='GET|POST|HEAD|PROPFIND|DELETE|PUT|MKCOL|MOVE|COPY|PROPPATCH|REPORT|UNLOCK|OPTIONS' \
-e X_FRAME_OPTIONS=SAMEORIGIN \
-e USE_GZIP=yes \
-e USE_BAD_BEHAVIOR=no \
-e WHITELIST_USER_AGENT='WebDAV iOS' \
-v ~/containers/nextcloud/html:/www:ro,z \
-v ~/containers/nextcloud/nginx/certs:/etc/letsencrypt:Z \
-v ~/containers/nextcloud/nginx/server-confs:/server-confs:ro,z \
-v ~/containers/nextcloud/nginx/modsec-crs-confs:/modsec-crs-confs:ro,z \
-v ~/containers/nextcloud/nginx/modsec-confs:/modsec-confs:ro,z \
bunkerity/bunkerized-nginx:1.2.7
Access the Nextcloud Admin setup
https://your.domain.name
Now we wait for the webserver to start, this may take minutes as it has to get certificates from Let's Encrypt and download security data. Afterwards that you should be able to browse to the initial Nextcloud admin setup page. If things take too long to start a re-start of the nextcloud_pod may be necessary to kick things off.
podman pod restart nextcloud_pod
If you cannot access the Nextcloud it's probably the Nginx server denying access, and podman logs will be your (possibly unwanted) friend.
podman logs nginx-bunkerized