Nginx documentation (Unofficial (Community) )

Nginx Configuration

Note: " in the web root" known to work with ownCloud 10.0-10.3 (older/newer versions as well as subdirectory config untested)

Introduction

This page covers example Nginx configurations to use with running an ownCloud server. Note that Nginx is not officially supported, and this page is community-maintained. Thank you, contributors!

  • Depending on your setup, you need to insert the code examples into your Nginx configuration file.
  • Adjust server_name, root, ssl_certificate, ssl_certificate_key ect. to suit your needs.
  • Make sure your SSL certificates are readable by the server (see Nginx HTTP SSL Module documentation).
  • Nginx configuration blocks inherit add_header directives from their enclosing blocks, so you just need to place the add_header directive in the top‑level server block. There’s one important exception:
    if a block includes an add_header directive itself, it does not inherit headers from enclosing blocks,
    and you need to redeclare all add_header directives or reinclude them.
  • Because Nginx does not allow nested if directives, you need to use the map directive.
    The position of a location directive connected to the result of the map directive is important for success.

TIP: For better readability, it is possible and advised to move common add_header directives into a separate file and include that file wherever necessary. However, each add_header directive must be written in a single line to prevent connection problems with sync clients.

TIP: The same is true for map directives which also can be collected into a singe file and then be included.

Example Configurations

CAUTION: Be careful about line breaks if you copy the examples, as long lines may be broken for page formatting.

You can use ownCloud over plain HTTP. However, we strongly encourage you to use SSL/TLS to encrypt all of your server traffic and to protect users’ logins, and their data while it is in transit. To use plain HTTP:

  1. Remove the server block containing the redirect
  2. Change listen 443 ssl http2 to listen 80;
  3. Remove all ssl_ entries.
  4. Remove fastcgi_params HTTPS on;

Note 1

fastcgi_buffers 8 4K;
  • Do not set the number of buffers to greater than 63. In our example, it is set to 8.
  • If you exceed this maximum, big file downloads may consume a lot of system memory over time. This is especially problematic on low-memory systems.

Note 2

fastcgi_ignore_headers X-Accel-Buffering
  • From ownCloud version 10.0.4 on, a header will be sent to Nginx not to use buffers to avoid problems with problematic fastcgi_buffers values. See note above.
  • If the values of fastcgi_buffers are properly set and no problems are expected, you can use this directive to reenable buffering overriding the sent header.
  • In case you use an earlier version of ownCloud or can´t change the buffers, or can´t remove a existing ignore header directive, you can explicitly enable following directive in the location block fastcgi_buffering off;

NOTE: The directives fastcgi_ignore_headers X-Accel-Buffering; and fastcgi_buffering off; can be used separately but not together.

Note 3

TIP: Raymii.org provides an excellent introduction to strong SSL security measures with Nginx.

ownCloud in the web root of Nginx

The following config should be used when ownCloud is placed in the web root of your Nginx installation.

The configuration assumes that ownCloud is installed in /var/www/owncloud and is accessed via http(s)://cloud.example.com.

upstream php-handler {
    server 127.0.0.1:9000;
    #server unix:/var/run/php7.2-fpm.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name cloud.example.com;

    # For SSL certificate verification, this needs to be served via HTTP
    location /.well-known/(acme-challenge|pki-validation)/ {
        root /var/www/owncloud; # Specify here where the challenge file is placed
    }

    # enforce https
    location / {
        return 301 https://$server_name:443$request_uri; # Change 443 if using a custom HTTPS port
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name cloud.example.com;

    ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
    ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;

    # Example SSL/TLS configuration. Please read into the manual of Nginx before applying these.
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "-ALL:EECDH+AES256:EDH+AES256:AES256-SHA:EECDH+AES:EDH+AES:!ADH:!NULL:!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!3DES:!PSK:!SRP:!DSS:!AESGCM:!RC4";
    ssl_dhparam /etc/nginx/dh4096.pem;
    ssl_prefer_server_ciphers on;
    keepalive_timeout    70;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Add headers to serve security related headers
    # The always parameter ensures that the header is set for all responses, including internally generated error responses.
    # Before enabling Strict-Transport-Security headers please read into this topic first.
    # https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

    #add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Robots-Tag "none" always;
    add_header X-Download-Options "noopen" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;

    # Path to the root of your installation
    root /var/www/owncloud/;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location = /.well-known/carddav {
        return 301 $scheme://$host:$server_port/remote.php/dav;
    }
    location = /.well-known/caldav {
        return 301 $scheme://$host:$server_port/remote.php/dav;
    }

    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 8 4K;                     # Please see note 1
    fastcgi_ignore_headers X-Accel-Buffering; # Please see note 2

    # Disable gzip to avoid the removal of the ETag header
    # Enabling gzip would also make your server vulnerable to BREACH
    # if no additional measures are done. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=773332
    gzip off;

    # Uncomment if your server is build with the ngx_pagespeed module
    # This module is currently not supported.
    #pagespeed off;

    error_page 403 /core/templates/403.php;
    error_page 404 /core/templates/404.php;

    location / {
        rewrite ^ /index.php$uri;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|changelog|data)/ {
        return 404;
    }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console|core/skeleton/) {
        return 404;
    }
    location ~ ^/core/signature\.json {
        return 404;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[sm]-provider/.+|core/templates/40[34])\.php(?:$|/) {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name; # necessary for ownCloud to detect the contextroot https://github.com/owncloud/core/blob/v10.0.0/lib/private/AppFramework/Http/Request.php#L603
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTPS on;
        fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
        fastcgi_param front_controller_active true;
        fastcgi_read_timeout 180; # increase default timeout e.g. for long running carddav/caldav syncs with 1000+ entries
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off; #Available since Nginx 1.7.11
    }

    location ~ ^/(?:updater|oc[sm]-provider)(?:$|/) {
        try_files $uri $uri/ =404;
        index index.php;
    }

    # Adding the cache control header for js and css files
    # Make sure it is BELOW the PHP block
    location ~ \.(?:css|js)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "max-age=15778463" always;

        # Add headers to serve security related headers (It is intended to have those duplicated to the ones above)
        # The always parameter ensures that the header is set for all responses, including internally generated error responses.
        # Before enabling Strict-Transport-Security headers please read into this topic first.
        # https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

        #add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Robots-Tag "none" always;
        add_header X-Download-Options "noopen" always;
        add_header X-Permitted-Cross-Domain-Policies "none" always;
        # Optional: Don't log access to assets
        access_log off;
    }

    location ~ \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg|map|json)$ {
        add_header Cache-Control "public, max-age=7200" always;
        try_files $uri /index.php$uri$is_args$args;
        # Optional: Don't log access to other assets
        access_log off;
    }
}

ownCloud in a subdirectory of Nginx

The following config should be used when ownCloud is placed under a different context root of your Nginx installation such as /owncloud or /cloud.

The configuration assumes that ownCloud is installed in /var/www/owncloud is accessed via http(s)://example.com/owncloud and that you have 'overwriteweb root' => '/owncloud', set in your config/config.php.

upstream php-handler {
    server 127.0.0.1:9000;
    #server unix:/var/run/php7.2-fpm.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name cloud.example.com;

    # For SSL certificate verification, this needs to be served via HTTP
    location /.well-known/(acme-challenge|pki-validation)/ {
        root /var/www/owncloud; # Specify here where the challenge file is placed
    }

    # enforce https
    location / {
        return 301 https://$server_name:443$request_uri; # Change 443 if using a custom HTTPS port
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name cloud.example.com;

    ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
    ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;

    # Example SSL/TLS configuration. Please read into the manual of Nginx before applying these.
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "-ALL:EECDH+AES256:EDH+AES256:AES256-SHA:EECDH+AES:EDH+AES:!ADH:!NULL:!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!3DES:!PSK:!SRP:!DSS:!AESGCM:!RC4";
    ssl_dhparam /etc/nginx/dh4096.pem;
    ssl_prefer_server_ciphers on;
    keepalive_timeout    70;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Add headers to serve security related headers
    # The always parameter ensures that the header is set for all responses, including internally generated error responses.
    # Before enabling Strict-Transport-Security headers please read into this topic first.
    # https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

    #add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Robots-Tag "none" always;
    add_header X-Download-Options "noopen" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;

    # Path to the root of your installation
    root /var/www/;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location = /.well-known/carddav {
        return 301 $scheme://$host:$server_port/owncloud/remote.php/dav;
    }
    location = /.well-known/caldav {
        return 301 $scheme://$host:$server_port/owncloud/remote.php/dav;
    }

    location ^~ /owncloud {

        # set max upload size
        client_max_body_size 512M;
        fastcgi_buffers 8 4K;                     # Please see note 1
        fastcgi_ignore_headers X-Accel-Buffering; # Please see note 2

        # Disable gzip to avoid the removal of the ETag header
        # Enabling gzip would also make your server vulnerable to BREACH
        # if no additional measures are done. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=773332
        gzip off;

        # Uncomment if your server is build with the ngx_pagespeed module
        # This module is currently not supported.
        #pagespeed off;

        error_page 403 /owncloud/core/templates/403.php;
        error_page 404 /owncloud/core/templates/404.php;

        location /owncloud {
            rewrite ^ /owncloud/index.php$uri;
        }

        location ~ ^/owncloud/(?:build|tests|config|lib|3rdparty|templates|changelog|data)/ {
            return 404;
        }
        location ~ ^/owncloud/(?:\.|autotest|occ|issue|indie|db_|console|core/skeleton/) {
            return 404;
        }
        location ~ ^/owncloud/core/signature\.json {
            return 404;
        }

        location ~ ^/owncloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|oc[sm]-provider/.+|core/templates/40[34])\.php(?:$|/) {
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME $fastcgi_script_name; # necessary for ownCloud to detect the context root https://github.com/owncloud/core/blob/v10.0.0/lib/private/AppFramework/Http/Request.php#L603
            fastcgi_param PATH_INFO $fastcgi_path_info;
            fastcgi_param HTTPS on;
            fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
            # EXPERIMENTAL: active the following if you need to get rid of the 'index.php' in the URLs
            #fastcgi_param front_controller_active true;
            fastcgi_read_timeout 180; # increase default timeout e.g. for long running carddav/caldav syncs with 1000+ entries
            fastcgi_pass php-handler;
            fastcgi_intercept_errors on;
            fastcgi_request_buffering off; #Available since Nginx 1.7.11
        }

        location ~ ^/owncloud/(?:updater|oc[sm]-provider)(?:$|/) {
            try_files $uri $uri/ =404;
            index index.php;
        }

        # Adding the cache control header for js and css files
        # Make sure it is BELOW the PHP block
        location ~ /owncloud/.*\.(?:css|js) {
            try_files $uri /owncloud/index.php$uri$is_args$args;
            add_header Cache-Control "max-age=15778463" always;

            # Add headers to serve security related headers (It is intended to have those duplicated to the ones above)
            # The always parameter ensures that the header is set for all responses, including internally generated error responses.
            # Before enabling Strict-Transport-Security headers please read into this topic first.
            # https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

            #add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;
            add_header X-Content-Type-Options "nosniff" always;
            add_header X-Frame-Options "SAMEORIGIN" always;
            add_header X-XSS-Protection "1; mode=block" always;
            add_header X-Robots-Tag "none" always;
            add_header X-Download-Options "noopen" always;
            add_header X-Permitted-Cross-Domain-Policies "none" always;
            # Optional: Don't log access to assets
            access_log off;
        }

        location ~ /owncloud/.*\.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg|map|json) {
            try_files $uri /owncloud/index.php$uri$is_args$args;
            add_header Cache-Control "public, max-age=7200" always;
            # Optional: Don't log access to other assets
            access_log off;
        }
    }
}
1 Like