The Issue - I'm getting a 404 - File not Found when trying to access the App (Including First Time)
When trying to access the App on a browser via nextcloud.example.com I'm getting this Error from the Console Log of the NextCloud FMP Docker Container:
172.19.0.5 - 04/Mar/2023:22:36:01 +0000 "GET /index.php" 404
And this error from the Console Log of the NGinX Docker Container:
172.69.67.108 - - [04/Mar/2023:22:36:01 +0000] "GET / HTTP/2.0" 404 36 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" "xxx.my.ip.xxx"
The setup of the Docker Server Host and the Containers
Docker Host Server OS is Ubuntu 22.04 LTS
NGinX Docker Container, I am aware that a docker-compose.yml is best, but for now and until I get this working properly, I'm running the Container with:
docker run -p 80:80 -p 443:443 --name nginx \ --restart=unless-stopped \ -v certbot:/etc/letsencrypt \ -v nginx:/etc/nginx/conf.d \ -v www:/usr/share/nginx/html \ --network tools \ -d nginx
This is the only Container on the Docker Server Host with Ports Exposed and uses volume mounts to share:
- Certificates with a CertBot Container
- NGinX Conf Directory to set up a conf for each app
- HTML www root home to share with the NextCloud FPM Docker Container
- Network Tools
NextCloud FPM Docker Container, I'm running the Container with:
docker run --name nextcloud-fpm \ --restart=unless-stopped \ -v www:/var/www/html \ -e 'TRUSTED_PROXIES=nginx' \ -e 'POSTGRES_HOST=database.server.com' \ -e 'POSTGRES_USER=database_user' \ -e 'POSTGRES_PASSWORD=database_user_password' \ -e 'POSTGRES_DB=databse_name' \ --network tools \ -d nextcloud:fpm
This Container is run on the same Network Tools, to not have to expose the app's Ports to the Docker Host Server, and to make it easier when it's time to create the Container Stacks and NGinX conf file by using the Container Names instead of IPs for Proxy Reverses
- HTML www root home to share with the NGinX Docker Container
- Environmental Variables for Trusted Proxy (the NGinX Container
- Environmental Variables for PostgreSQL Database
- This Cotainer runs FPM on Port 9000
- Network Tools
NGinX conf Files, there are 2 of them, one default.conf to mainly not allow the Host Server to be reached by IP directly and port (Example xxx.xxx.xxx.xxx:80 or xxx.xxx.xxx.xxx:443):
server { # Removes Web Server Info server_tokens off; # HTTP listen 80 default_server; listen [::]:80 default_server; listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; ssl_reject_handshake on; # Identify Server without the name, hence just IP server_name _; # Return Empty Response return 444; }
Finally the nextcloud.conf, it was taken form the GitHub NextCloud FPM Official Repo:
upstream php-handler { server nextcloud-fpm:9000; # In here I set up the Stream with the NextCloud FPM Container name } server { listen 80; listen [::]:80; server_name nextcloud.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name nextcloud.example.com; ssl_certificate /etc/letsencrypt/live/nextcloud.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/nextcloud.example.com/privkey.pem; # HSTS settings # WARNING: Only add the preload option once you read about # the consequences in https://hstspreload.org/. This option # will add the domain to a hardcoded list that is shipped # in all major browsers and getting removed from this list # could take several months. #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; # 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/> # 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 /usr/share/nginx/html/; # Since NGinX is the Web Server, I am pointing root to where the NextCloud Files are mounted inside the NGinX Container from the NextCloud FPM Container # 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 php-handler; 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; } }
What I have tried so far
My First instinct was to check the Logs, I shared them at the start of this post, and based on that I went to check if the Files were Present on both Containers, I did this in two different ways:
I have a Container of Portainer Running on the same Docker Host Server and also behind the sane NGinX Docker Container as Proxy Reverse, I attached a console and look for the files inside both Containers, also did
docker exec container_name -it bash
on both containers:NGinX Container, remember the mount was on
/usr/share/nginx/html
root@61564cff4e67:/# ls -lha /usr/share/nginx/html total 180K drwxrwxrwx 15 www-data www-data 4.0K Mar 4 13:24 . drwxr-xr-x 3 root root 4.0K Feb 9 04:36 .. -rw-r--r-- 1 www-data www-data 3.2K Mar 4 13:24 .htaccess -rw-r--r-- 1 www-data www-data 101 Mar 4 13:24 .user.ini drwxr-xr-x 47 www-data www-data 4.0K Mar 4 13:24 3rdparty -rw-r--r-- 1 www-data www-data 19K Mar 4 13:24 AUTHORS -rw-r--r-- 1 www-data www-data 34K Mar 4 13:24 COPYING drwxr-xr-x 50 www-data www-data 4.0K Mar 4 13:24 apps drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 config -rw-r--r-- 1 www-data www-data 4.0K Mar 4 13:24 console.php drwxr-xr-x 23 www-data www-data 4.0K Mar 4 13:24 core -rw-r--r-- 1 www-data www-data 6.2K Mar 4 13:24 cron.php drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 custom_apps drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 data drwxr-xr-x 2 www-data www-data 12K Mar 4 13:24 dist -rw-r--r-- 1 www-data www-data 156 Mar 4 13:24 index.html -rw-r--r-- 1 www-data www-data 3.4K Mar 4 13:24 index.php drwxr-xr-x 6 www-data www-data 4.0K Mar 4 13:24 lib -rwxr-xr-x 1 www-data www-data 283 Mar 4 13:24 occ drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocm-provider drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs-provider -rw-r--r-- 1 www-data www-data 3.1K Mar 4 13:24 public.php -rw-r--r-- 1 www-data www-data 5.5K Mar 4 13:24 remote.php drwxr-xr-x 4 www-data www-data 4.0K Mar 4 13:24 resources -rw-r--r-- 1 www-data www-data 26 Mar 4 13:24 robots.txt -rw-r--r-- 1 www-data www-data 2.4K Mar 4 13:24 status.php drwxr-xr-x 3 www-data www-data 4.0K Mar 4 13:24 themes -rw-r--r-- 1 www-data www-data 383 Mar 4 13:24 version.php
NextCloud FPM Container, remember the mount was on
/var/www/html
root@938c95d0e1ae:/var/www/html# ls -lha total 180K drwxrwxrwx 15 www-data www-data 4.0K Mar 4 13:24 . drwxrwxr-x 1 www-data root 4.0K Feb 16 03:06 .. -rw-r--r-- 1 www-data www-data 3.2K Mar 4 13:24 .htaccess -rw-r--r-- 1 www-data www-data 101 Mar 4 13:24 .user.ini drwxr-xr-x 47 www-data www-data 4.0K Mar 4 13:24 3rdparty -rw-r--r-- 1 www-data www-data 19K Mar 4 13:24 AUTHORS -rw-r--r-- 1 www-data www-data 34K Mar 4 13:24 COPYING drwxr-xr-x 50 www-data www-data 4.0K Mar 4 13:24 apps drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 config -rw-r--r-- 1 www-data www-data 4.0K Mar 4 13:24 console.php drwxr-xr-x 23 www-data www-data 4.0K Mar 4 13:24 core -rw-r--r-- 1 www-data www-data 6.2K Mar 4 13:24 cron.php drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 custom_apps drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 data drwxr-xr-x 2 www-data www-data 12K Mar 4 13:24 dist -rw-r--r-- 1 www-data www-data 156 Mar 4 13:24 index.html -rw-r--r-- 1 www-data www-data 3.4K Mar 4 13:24 index.php drwxr-xr-x 6 www-data www-data 4.0K Mar 4 13:24 lib -rwxr-xr-x 1 www-data www-data 283 Mar 4 13:24 occ drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocm-provider drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs-provider -rw-r--r-- 1 www-data www-data 3.1K Mar 4 13:24 public.php -rw-r--r-- 1 www-data www-data 5.5K Mar 4 13:24 remote.php drwxr-xr-x 4 www-data www-data 4.0K Mar 4 13:24 resources -rw-r--r-- 1 www-data www-data 26 Mar 4 13:24 robots.txt -rw-r--r-- 1 www-data www-data 2.4K Mar 4 13:24 status.php drwxr-xr-x 3 www-data www-data 4.0K Mar 4 13:24 themes -rw-r--r-- 1 www-data www-data 383 Mar 4 13:24 version.php
Docker Server Host Bind Mount Lastly to check the files o the Docker Host Server itself, as I do not only want to achieve sharing the root location for both Containers also have persistent data if I need to move the Container:
❯ ll total 180K drwxrwxrwx 15 www-data www-data 4.0K Mar 4 13:24 . drwxrwxr-x 10 Alejandro Alejandro 4.0K Mar 4 13:24 .. drwxr-xr-x 47 www-data www-data 4.0K Mar 4 13:24 3rdparty drwxr-xr-x 50 www-data www-data 4.0K Mar 4 13:24 apps -rw-r--r-- 1 www-data www-data 19K Mar 4 13:24 AUTHORS drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 config -rw-r--r-- 1 www-data www-data 4.0K Mar 4 13:24 console.php -rw-r--r-- 1 www-data www-data 34K Mar 4 13:24 COPYING drwxr-xr-x 23 www-data www-data 4.0K Mar 4 13:24 core -rw-r--r-- 1 www-data www-data 6.2K Mar 4 13:24 cron.php drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 custom_apps drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 data drwxr-xr-x 2 www-data www-data 12K Mar 4 13:24 dist -rw-r--r-- 1 www-data www-data 3.2K Mar 4 13:24 .htaccess -rw-r--r-- 1 www-data www-data 156 Mar 4 13:24 index.html -rw-r--r-- 1 www-data www-data 3.4K Mar 4 13:24 index.php drwxr-xr-x 6 www-data www-data 4.0K Mar 4 13:24 lib -rwxr-xr-x 1 www-data www-data 283 Mar 4 13:24 occ drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocm-provider drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs drwxr-xr-x 2 www-data www-data 4.0K Mar 4 13:24 ocs-provider -rw-r--r-- 1 www-data www-data 3.1K Mar 4 13:24 public.php -rw-r--r-- 1 www-data www-data 5.5K Mar 4 13:24 remote.php drwxr-xr-x 4 www-data www-data 4.0K Mar 4 13:24 resources -rw-r--r-- 1 www-data www-data 26 Mar 4 13:24 robots.txt -rw-r--r-- 1 www-data www-data 2.4K Mar 4 13:24 status.php drwxr-xr-x 3 www-data www-data 4.0K Mar 4 13:24 themes -rw-r--r-- 1 www-data www-data 101 Mar 4 13:24 .user.ini -rw-r--r-- 1 www-data www-data 383 Mar 4 13:24 version.php root@myserver /mnt/Volume/data/www
I see no reason why permission wise it would not work and have confirmed that the files are present in all three instances as they should.
Check the NGinX conf file for NextCloud FPM nextcloud.conf, after a lot of consideration the only thing I think can be wrong since I'm reaching via the domain on a browser all the way to the NGniX Web Server Container, as I have 404 Not Found entries in its log and I'm also getting a response from the NextCloud Container instance itself a 404 Not Found as well, that the only problem I have is related to the root entry on the conf file:
NextCloud Log:
172.19.0.5 - 04/Mar/2023:22:36:01 +0000 "GET /index.php" 404
NGinX Log:
172.69.67.108 - - [04/Mar/2023:22:36:01 +0000] "GET / HTTP/2.0" 404 36 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" "xxx.my.ip.xxx"
So I changed the root directive to be
/var/www/html
, and the behavior changes just a bit, I'm still getting a 404 Not Found entry but only on the NGinX Web Server Container logs, the NextCloud Container is silent, so I'm not reaching it with this change:NextCloud Log (empty no entry at all):
NGinX Log:
2023/03/05 00:13:24 [error] 473#473: *4152 "/var/www/html/index.php" is not found (2: No such file or directory), client: 172.69.65.73, server: nextcloud.example.com, request: "GET / HTTP/2.0", host: "nextcloud.example.com" 172.69.65.73 - - [05/Mar/2023:00:13:24 +0000] "GET / HTTP/2.0" 404 174 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" "xxx.my.ip.xxx"
There's something different in the way the Web Server behaves, I notice that after the root directive change, I see the actual domain between quotes on the log
"nextcloud.example.com"
when before was just a dash"-"
.Next thing was to just disable default.conf NGinX conf file, as is the only place I can think of the
"-"
, same results as above and I repeated on both scenarios 1 and 2 I have already tried, it is a"_"
on the server directive of the default.conf too so was a shot in the dark.I have tried many other settings with the conf but most of them end up being
Too Many Redirections
,Bad Certificate
, or just plain502
errors.
My Determination of What the Problem and Where I'm stuck
It seems I'm very close to my desired result, as I am reaching both Containers from browsers with the desired domain, and SSL is resolving fine as well, however, the server name doesn't seem to be captured by the NGinX conf file, and then not passed correctly to NextCloud, but I don't know what exactly to change.
Since I think I narrowed it down to what I think is the specific issue maybe someone can help me review the NGinX conf file nextcloud.conf and point out what is set wrong.
Thanks, for even reading this long post.