docker icon indicating copy to clipboard operation
docker copied to clipboard

Nextcloud fpm running on docker with nginx on host always returns 404 page

Open Laikar opened this issue 4 years ago • 7 comments

I'm trying to install nextcloud using the fpm docker compose image with nginx as the proxy runing natively on the host, but when i conect to my domain, nginx returns a 404. At first it thought it was the database, because according to docker logs the container couldn't connect to the database, but after finxing it the problem still persists.

All i get from docker logs is

[14-Dec-2021 06:33:44] NOTICE: fpm is running, pid 1
[14-Dec-2021 06:33:44] NOTICE: ready to handle connections

This is the docker compose file i'm using

version: '3'

volumes:
  nextcloud:

services:
  nextcloud:
    container_name: nextcloud
    image: nextcloud:23.0-fpm-alpine
    restart: always
    ports:
      - "8081:9000"
    networks:
      - default

    volumes:
      - /opt/nextcloud/data:/var/www/html
    environment:
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=cloud
      - MYSQL_HOST=172.21.0.1:3306
      - NEXTCLOUD_ADMIN_USER=Laikar
      - NEXTCLOUD_ADMIN_PASSWORD=password
networks:
  default:
    driver: "bridge"
    ipam:
      config:
        - subnet: 172.21.0.0/16
          gateway: 172.21.0.1

and this is the nginx config file, i copied it from the examples

upstream nextcloud {
    server 127.0.0.1:8081;
}

server {
    listen              443 ssl http2;
    listen              [::]:443 ssl http2;
    #i have the correct domain on the configs
    server_name         example.domain;
    # SSL
    # and these do point to valid certificates and keys on my config
    ssl_certificate     /some/ssl/certificate;
    ssl_certificate_key /some/ssl/key;


     # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    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;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    #pagespeed off;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    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;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Path to the root of your installation
    root /var/www/html;

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    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;
    }

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in `.htaccess` that concern `/.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; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /index.php$request_uri;
    }

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        # Required for legacy support
        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 $document_root$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;

        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`
        access_log off;     # Optional: Don't log access to assets
    }

    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets
    }

    # Rule borrowed from `.htaccess`
    location /remote {
        return 301 /remote.php$request_uri;
    }

    location / {
        try_files $uri $uri/ /index.php$request_uri;
    }

}

Laikar avatar Dec 14 '21 07:12 Laikar

 volumes:
      - /opt/nextcloud/data:/var/www/html

As the nginx is in host itself, the web root should be at /opt/nextcloud/data

nextcloud fpm docker write to /var/www/html , /var/www/html in nextcloud fpm linked to /opt/nextcloud/data in host, nginx host should read data in host that is /opt/nextcloud/data not /var/www/html

martadinata666 avatar Dec 14 '21 07:12 martadinata666

I tried that, but it turns the nginx 404 response to just a blank page with the text "File not found" with /var/www/html as document root there are no errors on nginx error.log but with /opt/nextcloud/data a bunch of these start appearing

2021/12/14 07:43:17 [error] 48715#48715: *1 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 81.23.45.67, server: example.domain, request: "GET / HTTP/2.0", upstream: "fastcgi://127.0.0.1:9000", host: "example.domain"

Laikar avatar Dec 14 '21 07:12 Laikar

Oh, seems docker fpm with host nginx cant combined. As both looking different web root, Either both /var/www/html, or use use nginx with fpm in one compose, and let nginx in redirect.

martadinata666 avatar Dec 14 '21 08:12 martadinata666

Hello, I am testing Nextcloud with the same setup seeing the same error on a fresh installation similar to OP: nginx on host, nextcloud in docker alpine launched with:

docker run --rm -p 9000:9000 nextcloud:23.0.0-fpm-alpine

I am not using docker compose.

My nginx configuration is identical to the first comment, I set the root to: root /opt/nextcloud/html;. In that directory I have decompressed the tar.gz of the latest nextcloud release.

However in the logs I see the same error:

2022/01/03 00:09:33 [error] 26439#26439: *3674 FastCGI sent in stderr: "Primary script unknown" 
while reading response header from upstream, client: 111.222.333.444, server: example.com, 
request: "GET / HTTP/2.0", upstream: "fastcgi://127.0.0.1:9000", host: "example.com"

Oh, seems docker fpm with host nginx cant combined. As both looking different web root, Either both /var/www/html, or use use nginx with fpm in one compose, and let nginx in redirect.

@martadinata666 I afraid I don't have clear your suggestion, can you please elaborate on what is the issue? Does the FastCGI redirect can work with a dockerized Nextcloud instance or it's not possible? What does that error actually means?

thank you!

apiraino avatar Jan 02 '22 23:01 apiraino

I think I've solved this issue, at least it Works For Me (:copyright: 2022). I'll detail my solution, though not sure is applicable for @Laikar.

First, I had to change this line in the nginx configuration. For some reason the suggested config (for example here) does not work for me:

# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php

Note: this was likely the main culprit.

Then ensure that the directories on the host where Nextcloud will write have ownership to www-data:www-data

Finally, I could successfully start the container:

docker run -d --name nc23.0.0 \
   # this must match `www-data:www-data` on the host
    -u 33:33 \
    # this is the passthrough for php FastCGI on nginx 
    -p 9000:9000 \
    -e SQLITE_DATABASE=nc.sqlite3 \
    -e NEXTCLOUD_TRUSTED_DOMAINS=example.com \
   # Mapping paths from the host to those inside the container
    -v /path/host/nextcloud/html:/var/www/html \
    -v /path/host/nextcloud/data:/var/www/html/data \
    -v /path/host/nextcloud/config:/var/www/html/config \
    nextcloud:23.0.0-fpm-alpine

This config can be expressed with a docker-compose file:

version: '3.8'

networks:
    nextcloud:
        external: false

services:
    nextcloud:
        image: nextcloud:23.0.0-fpm-alpine
        # must match `www-data:www-data` on the host
        # see: `grep www-data /etc/passwd`
        user: '33:33'
        environment:
          # path inside container: `/var/www/html/data`
          # created on the host: `/opt/nextcloud/data`
          - SQLITE_DATABASE=nc.sqlite3
          - NEXTCLOUD_TRUSTED_DOMAINS=example.com
        ports:
          - 9000:9000
        volumes:
          - /opt/nextcloud/html:/var/www/html
          - /opt/nextcloud/data:/var/www/html/data
          - /opt/nextcloud/config:/var/www/html/config
        restart: unless-stopped
        networks:
          - nextcloud

hth!

apiraino avatar Jan 03 '22 15:01 apiraino

So basically i do something like this, so we only expose nginx to outside, further just add some reverse proxy like swag or npm in front of out nextcloud nginx.

version: "3.5"
services:
  db:
   image: mariadb:10.5
   user: 1000:1000
   environment:
      - MYSQL_ROOT_PASSWORD=mariadbroot
      - TZ=Asia/Jakarta
      - MYSQL_DATABASE=nc
      - MYSQL_USER=ncuser
      - MYSQL_PASSWORD=ncpass
   volumes:
      - ./db:/var/lib/mysql
   restart: unless-stopped
   networks:
      - nc
      
 fpm:
    image: nextcloud/bla3-fpm
    user: 1000:1000
    environment:
      - TZ=Asia/Jakarta
    volumes:
      - nfs-htdocs:/var/www/html
    restart: unless-stopped
    networks:
      - nc
      
  nginx:
    image: nginx
    user: 1000:1000
    volumes:
      - nfs-htdocs:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    ports:
      - 8080:80
  
networks:
  nc:
    name: nc

volumes:
  nfs-htdocs:
    driver_opts:
      type: "nfs4"
      o: "addr=192.168.0.2,rw,noatime,timeo=14,nolock"
      device: ":/home/dedyms/docker/webmail/www"

Override nginx default settings by copy from nextcloud sample, change the fastcgi_pass fpm:9000; and root dir to /var/www/html

martadinata666 avatar Jan 04 '22 12:01 martadinata666

I think I've solved this issue, at least it Works For Me (©️ 2022). I'll detail my solution, though not sure is applicable for @Laikar.

First, I had to change this line in the nginx configuration. For some reason the suggested config (for example here) does not work for me:

# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php

Note: this was likely the main culprit.

Then ensure that the directories on the host where Nextcloud will write have ownership to www-data:www-data

Finally, I could successfully start the container:

docker run -d --name nc23.0.0 \
   # this must match `www-data:www-data` on the host
    -u 33:33 \
    # this is the passthrough for php FastCGI on nginx 
    -p 9000:9000 \
    -e SQLITE_DATABASE=nc.sqlite3 \
    -e NEXTCLOUD_TRUSTED_DOMAINS=example.com \
   # Mapping paths from the host to those inside the container
    -v /path/host/nextcloud/html:/var/www/html \
    -v /path/host/nextcloud/data:/var/www/html/data \
    -v /path/host/nextcloud/config:/var/www/html/config \
    nextcloud:23.0.0-fpm-alpine

This config can be expressed with a docker-compose file:

version: '3.8'

networks:
    nextcloud:
        external: false

services:
    nextcloud:
        image: nextcloud:23.0.0-fpm-alpine
        # must match `www-data:www-data` on the host
        # see: `grep www-data /etc/passwd`
        user: '33:33'
        environment:
          # path inside container: `/var/www/html/data`
          # created on the host: `/opt/nextcloud/data`
          - SQLITE_DATABASE=nc.sqlite3
          - NEXTCLOUD_TRUSTED_DOMAINS=example.com
        ports:
          - 9000:9000
        volumes:
          - /opt/nextcloud/html:/var/www/html
          - /opt/nextcloud/data:/var/www/html/data
          - /opt/nextcloud/config:/var/www/html/config
        restart: unless-stopped
        networks:
          - nextcloud

hth!

Highly appreciate the answer from you, and it inspires me a lot.

But there is a little point you can improve for the nginx config, you recommend to do this: fastcgi_param SCRIPT_FILENAME /var/www/html/index.php But it's better for you to do like this: fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name

For the function of fascgi_parm is to allow nginx pass information to php-fpm, and SCRIPT_FILENAME is nginx telling php-fpm where the php scripts are.

param in origin config $document_root is point to the parm of root in nginx config, in the nginx config file example the root is /var/www/nextcloud, but in docker container the actual file path is /var/www/html. So this is the main point.

As for param of $fastcgi_script_name is the name of script. Like if the url is 'http://example.com/index.php', the value of this param will be index.php. But in your config, you just directly write index.php. If there are some request like 'http://example.com/index1.php', you will not handle it, but use $fastcgi_script_name you can do that.

sujoshua avatar Sep 11 '22 16:09 sujoshua

Sounds similar to https://github.com/nextcloud/docker/issues/398.

iceton avatar Dec 16 '22 08:12 iceton