I have set up a Nextcloud install behind a nginx reverse proxy. I have discovered that various parts of Nextcloud no longer function, such as impersonating users and sending Talk messages. What’s confusing is that all resources are being loaded and the rest of Nextcloud works.
I created my nginx config following the documentation.
Impersonating users:
Sending Talk message:
error while submitting message Error: Request failed with status code 403
nginx config
upstream backend_hosts
{
server 192.168.0.99:443;
}
server
{
listen 80;
listen [::]:80;
server_name nc.example.com;
return 301 https://$server_name$request_uri;
}
server
{
listen 443 ssl;
listen [::]:443 ssl;
server_name nc.example.com;
access_log /var/log/nginx/nc-example.log;
# proxy config
proxy_ssl_verify off; # dont check if the proxied server has a valid ssl cert
# increase the proxy timeout for long file operations
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 36000s;
send_timeout 600;
# set special proxy headers
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
# send all traffic to the backend server
location /
{
proxy_pass https://backend_hosts/index.php$request_uri;
}
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
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;
# proxy robots.txt
location = /robots.txt
{
allow all;
log_not_found off;
proxy_pass https://backend_hosts/robots.txt;
}
# 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 following 6 rules are borrowed from `.htaccess`
rewrite ^/\.well-known/host-meta\.json /public.php?service=host-meta-json last;
rewrite ^/\.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/\.well-known/webfinger /public.php?service=webfinger last;
rewrite ^/\.well-known/nodeinfo /public.php?service=nodeinfo last;
location = /.well-known/carddav
{
return 301 /remote.php/dav/;
}
location = /.well-known/caldav
{
return 301 /remote.php/dav/;
}
try_files $uri $uri/ =404;
}
# 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;
}
# 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;
# proxy some special urls to the backend server, these may not be caught by the default location
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/)
{
proxy_pass https://backend_hosts;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/)
{
proxy_pass https://backend_hosts;
}
# cache control for files
location ~ \.(?:css|js|woff2?|svg|gif|map)$
{
proxy_pass https://backend_hosts$request_uri;
add_header Cache-Control "public, max-age=15778463";
expires 6M; # Cache-Control policy borrowed from `.htaccess`
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$
{
proxy_pass https://backend_hosts/index.php$request_uri;
expires 7d; # Cache-Control policy borrowed from `.htaccess`
}
# Certbot SSL stuff goes here
ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}