Installation Problems with Nextcloud-FPM and Nginx on Docker Compose

I used to have a NextCloud Instance on my home server where I deployed nextcloud, redis and mariadb from docker, and used nginx from the host as the reverse proxy. I just recently discovered that I can put all these systems together in a single docker compose file, without me needing to install additional stuff on the host with apt. So, this was the docker-compose.yaml I came up with.

services:
  nginx:
    image: nginx:alpine
    container_name: nextcloud-nginx
    restart: unless-stopped
    volumes:
      - /mnt/SysHDD/Docker-Compose/nextcloud/nginx/:/etc/nginx/:rw
      - /home/server-inspiron/.acme.sh/:/mnt/certs/:ro
    ports:
      - 443:9000
      - 8096:81
      - 8920:82
    networks:
      nextcloud:
        ipv4_address: 172.21.128.4
  mariadb:
    image: mariadb
    container_name: nextcloud-mariadb
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
    volumes:
      - /mnt/SysHDD/Databases/nextcloud-mariadb/:/var/lib/mysql/:rw
    env_file:
      - db.env
    networks:
      nextcloud:
        ipv4_address: 172.21.128.1

  redis:
    image: redis
    container_name: nextcloud-redis
    restart: always
    command: redis-server --requirepass SOMEPASSWORD
    networks:
      nextcloud:
        ipv4_address: 172.21.128.2
  app:
    image: nextcloud:fpm
    restart: unless-stopped
    container_name: nextcloud-web
    ports:
      - 8080:9000
    links:
      - mariadb
      - redis
    volumes:
      - web:/var/www/html
    environment:
      - MYSQL_HOST=172.21.128.1:3306
      - REDIS_HOST_PASSWORD=SOMEPASSWORD
    env_file:
      - db.env
    depends_on:
      - mariadb
      - redis
    networks:
      nextcloud:
        ipv4_address: 172.21.128.3
volumes:
  nextcloud-mariadb:
  web:
networks:
  nextcloud:
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.0.0/16
          gateway: 172.21.0.1

As you can see, The configuration is similar to the regular apache version of the nextcloud docker install, only difference being I included an alpine nginx image and the fpm version of nextcloud. Ignore the opened ports 8096 and 8920, as they are for redirect policies for an Emby media instance.
I knew that the fpm version requires a reverse proxy, so I forwarded port 9000, which is default for nextcloud:fpm to host port 443 for https.

I am ignoring discussion about certificates because I am not using a service like certbot. I am giving myself a better power control over it with acme.sh.

To forward the app, this was my nginx.conf:

events {}
http {
  server {
      server_name mprakash.dynv6.net www.mprakash.dynv6.net;
      listen 82 ssl;
      listen 81;
#      listen 9000 ssl;   
      return 301 https://mprakash.dynv6.net:2$request_uri;
      ssl_certificate     /mnt/certs/mprakash.dynv6.net_ecc/mprakash.dynv6.net.pem;
      ssl_certificate_key /mnt/certs/mprakash.dynv6.net_ecc/mprakash.dynv6.net.key;
  }
upstream nextcloud {
    server 127.0.0.1:9000;
}

server {
    listen              443 ssl;
    listen              [::]:443 ssl;
    server_name         serverinspiron-cloud.dynv6.net;
    ssl_certificate     /mnt/certs/serverinspiron-cloud.dynv6.net_ecc/serverinspiron-cloud.dynv6.net.pem;
    ssl_certificate_key /mnt/certs/serverinspiron-cloud.dynv6.net_ecc/serverinspiron-cloud.dynv6.net.key;
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;
    fastcgi_hide_header X-Powered-By;
    root /var/www/html;
	if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
    index index.php index.html /index.php$request_uri;
    location = / {
        if ( $http_user_agent ~ ^DavClnt ) {
            return 302 /remote.php/webdav/$is_args$args;
        }
    }
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
    location ^~ /.well-known {
        location = /.well-known/carddav { return 301 /remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /remote.php/dav/; }
        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }
        return 301 /index.php$request_uri;
    }
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }
    location ~ \.php(?:$|/) {
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;
        try_files $fastcgi_script_name =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass localhost:9000;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
    }
    location ~ \.(?:css|js|svg|gif)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;
        access_log off;
    }
    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;
        access_log off;
    }
    location /remote {
        return 301 /remote.php$request_uri;
    }
    location / {
        try_files $uri $uri/ /index.php$request_uri;
    }
}
}

The configuration I am using is almost same as the nginx configuration in the nextcloud documentations.

I start the containers using docker compose up, and check the logs.
Logs for Nginx:

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up

So far, so good.

Logs for Nextcloud:

=> Searching for scripts (*.sh) to run, located in the folder: /docker-entrypoint-hooks.d/before-starting
[31-Oct-2024 07:26:01] NOTICE: fpm is running, pid 1
[31-Oct-2024 07:26:01] NOTICE: ready to handle connections

Looks fine too.

But the problem arises when I try to open the app on my browser. When I try to do so, I get the following error:

The connection is forcefully closed, which means something exists on the other side, but I am unable to access it. What is the problem that I am facing? I think it has a pretty trivial solution but I am unable to figure it out. I request the community to please help me out. Thank you.

you docker compose includes useless complexity e.g. I would avoid fixed IPs.

I would recommend starting with official Nginx reverse proxy example and more sophisticated Nextcloud docker compose setup with Caddy (2024)

your dyndnsv6 makes me think the problem might result from the fact Docker doesn’t serv ipv6 by default. Look through the topics we covered similar issue shortly.

1 Like

Your stack won’t work as you’ve defined it. An FPM deployment is fundamentally very different from deploying the Apache image. Deploying with FPM requires a web container that shares the same /var/www/html volume from the the app container.

I agree with, @wwe. I would simplify first. Even starting with the really simple example here that is FPM based for that image. That’ll help you get a better idea of what is going on. And can be built on for more complex needs as you test the impact of each change.

I FOUND THE SOLUTION!

@jtr and @wwe gave me wonderful insights into how I should structure my docker compose file, and I realised I just had to include the path of the webroot of the nextcloud installation into the nginx volume. that pretty much solved the entire problem. Thank you so much both of you!

1 Like

This topic was automatically closed 8 days after the last reply. New replies are no longer allowed.