# ============================================================ # Nextcloud - nginx (Docker) default.conf # - Single file, no includes, no compose changes # - Upstream: nextcloud-fpm-v1:9000 # - Well-known + OCS/OCM fixes # - Collabora prepared (commented) # - No HTTP/2 assumptions (host terminates TLS) # ============================================================ # Upstream PHP-FPM in Docker (keepalive for throughput) upstream php_nextcloud { server nextcloud-fpm-v1:9000 max_fails=3 fail_timeout=5s; keepalive 10; } # Upgrade mapping for potential websocket use later (e.g., Collabora) map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { # App-nginx listens only inside the container listen 8080; server_name _; # Nextcloud docroot from the mounted volume root /var/www/html; # Log to stdout/stderr for `docker logs` access_log /dev/stdout; error_log /dev/stderr warn; # --- Security headers (HSTS/OCSP etc. should be handled by host proxy) --- 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 "noindex, nofollow" always; add_header X-XSS-Protection "1; mode=block" always; fastcgi_hide_header X-Powered-By; # Fix für Nextcloud Self-Tests (PHP curl intern) proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Ssl on; # --- Client / FastCGI tuning --- # Match your PHP env (PHP_UPLOAD_LIMIT=10G) client_max_body_size 10g; fastcgi_buffers 64 4k; fastcgi_read_timeout 3600s; fastcgi_send_timeout 3600s; fastcgi_request_buffering off; gzip off; # per Nextcloud recommendation (preserve ETag) # --- Docker internal resolver for self-connect checks --- resolver 127.0.0.11 valid=30s; resolver_timeout 5s; # --- Real client IP from host reverse proxy --- set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; # --- Minimal type additions for modern JS & sourcemaps --- # (keine globalen mime.types nötig – wir ergänzen nur, was gebraucht wird) types { font/otf otf; text/html html htm shtml; text/css css; text/javascript js; application/javascript mjs; application/json json; application/manifest+json webmanifest; application/wasm wasm; application/octet-stream map; font/woff woff; font/woff2 woff2; image/svg+xml svg; image/png png; image/jpeg jpg jpeg; image/gif gif; text/plain txt; } # --- Serve .mjs and .js.map correctly (fixes admin checks) --- location ~* \.mjs$ { default_type application/javascript; try_files $uri $uri/ =404; access_log off; expires 1d; } location ~* \.js\.map$ { default_type application/octet-stream; try_files $uri =404; access_log off; expires 1d; } # --- robots.txt --- location = /robots.txt { allow all; log_not_found off; access_log off; } # --- .well-known handling (webfinger + cal/carddav + generic) --- location ~ ^/\.well-known/(acme-challenge/.*)$ { allow all; } location = /.well-known/carddav { return 301 $scheme://$host/remote.php/dav; } location = /.well-known/caldav { return 301 $scheme://$host/remote.php/dav; } location ^~ /.well-known { return 301 /index.php$uri; } location = /.well-known/webfinger { return 301 /index.php$uri; } # --- Deny sensitive dirs, as per Nextcloud docs --- location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ { deny all; } location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { deny all; } # ============================================================ # OCS/OCM PROVIDER FIXES # ------------------------------------------------------------ # 1) Some NC checks expect /ocs-provider/ to return a valid JSON. # We provide a tiny static JSON (no PHP needed), satisfying the check. location = /ocs-provider/ { default_type application/json; return 200 '{"version":"1.0","status":"ok"}'; } location = /ocs-provider/index.php { default_type application/json; return 200 '{"version":"1.0","status":"ok"}'; } # 2) Ensure ocs/ocm provider paths resolve to index.php for dynamic routes. location ~ ^/(?:ocs-provider|ocm-provider)(?:$|/) { try_files $uri /index.php$uri$is_args$args; } # ============================================================ # --- Main entry: route everything through front controller --- location / { rewrite ^ /index.php; } # --- PHP handling: main Nextcloud endpoints --- location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[sm]-provider/.+|core/templates/40[34])\.php(?:$|/) { include fastcgi_params; fastcgi_split_path_info ^(.+\.php)(/.*)$; try_files $fastcgi_script_name =404; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; # avoid duplicate security headers fastcgi_param modHeadersAvailable true; fastcgi_param front_controller_active true; fastcgi_pass php_nextcloud; fastcgi_intercept_errors on; } location ^~ /apps/ { try_files $uri /index.php$request_uri; } # --- Static assets caching (below PHP block) --- location ~* \.(?:css|js)$ { try_files $uri /index.php$uri$is_args$args; add_header Cache-Control "public, max-age=7200"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; access_log off; expires 2h; } location ~ \.woff2?$ { try_files $uri /index.php$request_uri; expires 7d; access_log off; } location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ { try_files $uri /index.php$uri$is_args$args; access_log off; expires 7d; } # ------------------------------------------------------------ # Collabora (prepared; keep commented until subdomain is live) # ------------------------------------------------------------ # location ^~ /loleaflet { # proxy_pass https://collabora.knusperkerne.de; # proxy_set_header Host $http_host; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection $connection_upgrade; # proxy_read_timeout 3600s; # proxy_buffering off; # } # location ^~ /lool { # proxy_pass https://collabora.knusperkerne.de; # proxy_set_header Host $http_host; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection $connection_upgrade; # proxy_http_version 1.1; # proxy_read_timeout 3600s; # proxy_buffering off; # } # Simple health endpoint location = /health { return 200 'ok'; add_header Content-Type text/plain; } }