Nextcloud fpm running on docker with nginx on host always returns 404 page
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;
}
}
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
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"
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.
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!
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!
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
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.phpNote: this was likely the main culprit.
Then ensure that the directories on the host where Nextcloud will write have ownership to
www-data:www-dataFinally, 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-alpineThis 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: - nextcloudhth!
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.
Sounds similar to https://github.com/nextcloud/docker/issues/398.