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:

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)

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