Setting Up Nginx for Nextcloud: A Known Good Configuration
Setting up Nextcloud with Nginx can seem complex, but with the right configuration, you can achieve a secure and highly efficient environment. In this blog, we’ll go through a working Nginx configuration for Nextcloud, breaking down each section for clarity. We’ll also cover specific considerations such as setting up Collabora Server access and handling .mjs
files that are essential for a smooth Nextcloud operation on both ARM and x86 platforms.
Basic Configuration for Nextcloud with Nginx
Before we begin, this tutorial assumes that you already have an Nginx server running with a fully qualified domain name (FQDN) and SSL configured. If not, follow any good tutorial like this. With that in place, let’s move on to setting up Nextcloud for maximum performance and security.
Let’s start with a well-tested Nextcloud Nginx configuration. This setup includes HTTP/2, SSL, security headers, gzip compression, and error handling to ensure both performance and security. Here’s the configuration:
####NEXTCLOUD CONFIG START######
server {
listen 80;
listen [::]:80;
http2 on;
server_name your.domain.com;
# Enforce HTTPS
return 301 https://$server_name:443$request_uri;
}
server {
# Port configuration
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# SSL configuration
ssl_certificate /etc/ssl/cert_cf.pem;
ssl_certificate_key /etc/ssl/key_cf.pem;
ssl_prefer_server_ciphers on;
# HSTS configuration
add_header Strict-Transport-Security "max-age=31536000" always;
server_name your.domain.com;
# Security headers
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;
# Hide X-Powered-By header
fastcgi_hide_header X-Powered-By;
# Path to your Nextcloud installation
root /var/www/nextcloud/;
# Log files
access_log /var/log/nginx/nextcloud.access;
error_log /var/log/nginx/nextcloud.error;
# Max upload size
client_max_body_size 1024M;
fastcgi_buffers 64 4K;
# Enable gzip compression
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;
# Error handling
error_page 404 403 /404.php;
location = /404.php {
root /var/www/error_pages/;
include fastcgi_params;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
internal;
}
# Deny access to sensitive directories
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
# Handle PHP files
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[ms]-provider/.+|.+/richdocumentscode_arm64/proxy).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;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
# Cache control for assets
location ~ \.(?:css|js|mjs|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
try_files $uri /index.php$request_uri;
access_log off;
}
location / {
rewrite ^ /index.php;
}
}
####NEXTCLOUD CONFIG END######
Key Configuration Highlights
1. HTTPS Enforcement and Security
The configuration starts by forcing HTTP to HTTPS redirection, ensuring secure communication with the client. Additionally, the HSTS (HTTP Strict Transport Security) header ensures browsers only communicate over HTTPS for future requests:
add_header Strict-Transport-Security "max-age=31536000" always;
Various other security headers like X-Content-Type-Options
, X-Frame-Options
, and X-XSS-Protection
help prevent clickjacking, XSS attacks, and MIME sniffing.
2. Collabora Server Access
When integrating Nextcloud with Collabora (used for document editing), you need to configure Nginx to correctly route the Collabora document server requests. If you’re running on an ARM processor, like Ampere Altra or Qualcomm, ensure that you’re using the correct richdocumentscode_arm64
proxy path.
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[ms]-provider/.+|.+/richdocumentscode_arm64/proxy).php(?:$|/) {
Using richdocumentscode
(meant for x86 servers) on an ARM CPU will result in errors. Always verify that you’re using the appropriate Collabora package for your architecture.
3. .mjs
File Handling for Nextcloud
Nextcloud can have issues handling .mjs
(ES Module JavaScript) files if not properly configured. In the default setup, only .js
files are handled. However, .mjs
files are critical for the modern JavaScript ecosystem, especially in Nextcloud apps. To avoid errors such as downloads instead of file rendering, add .mjs
to the asset handling location:
location ~ \.(?:css|js|mjs|woff2?|svg|gif|map)$ {
Without this addition, Nextcloud may not properly display or render certain files, instead forcing the browser to download them.
Additional Considerations
Caching and Compression
This configuration includes Gzip compression, which reduces the size of files sent over the network, leading to faster load times:
gzip on;
gzip_vary on;
gzip_comp_level 4;
Make sure to include the most commonly used file types in the gzip_types
directive to optimize bandwidth.
Error Handling
Custom error pages are defined in this configuration. For instance, a 404 error will serve a custom page instead of the default Nginx error page:
error_page 404 403 /404.php;
This can be tailored to match your site’s design and branding.