Nextcloud 13, Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy


If you are interested in running Nextcloud in parallel to Roundcube, WordPress, Shellinabox, Pi-hole and so on behind a NGINX reverse proxy you will find all the neccessary changes and configuration files below as an ammendment to the initial guide (Nextcloud 13 installation guide/Nextcloud 13 Installationsleitfaden). This configuration leads to an A+ rating and all Nextcloud checks will be successfully passed. You only have to ammend the red marked values (YOUR.DEDYN.IO, 192.168.2.x, 86) regarding your environment!


First move the existing nginx.conf and create a new file:

sudo -s
mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
vi /etc/nginx/nginx.conf

Paste all the following rows:

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
server_names_hash_bucket_size 64;
upstream php-handler {
server unix:/run/php/php7.2-fpm.sock;
}
set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
include /etc/nginx/mime.types;
include /etc/nginx/optimization.conf;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$host" sn="$server_name" '
'rt=$request_time '
'ua="$upstream_addr" us="$upstream_status" '
'ut="$upstream_response_time" ul="$upstream_response_length" '
'cs=$upstream_cache_status' ;
access_log /var/log/nginx/access.log main;
sendfile on;
send_timeout 3600;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=500 inactive=10m;
open_file_cache_errors on;
keepalive_timeout 65;
reset_timedout_connection on;
server_tokens off;
resolver 192.168.2.1;
resolver_timeout 10s;
include /etc/nginx/conf.d/*.conf;
}

Create the new file “gateway.conf” that will handle the incomming http(s)-requests to the server(s) behind the proxy:

vi /etc/nginx/conf.d/gateway.conf

Paste the following rows

server {
listen 80 default_server;
server_name placeholder;
location ^~ /.well-known/acme-challenge {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2 default_server;
server_name placeholder;
include /etc/nginx/ssl.conf;
include /etc/nginx/header.conf;
###NEXTCLOUD###
location ^~ / {
client_max_body_size 10G;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
proxy_buffering on;
proxy_max_temp_file_size 10240m;
proxy_request_buffering on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:82;
proxy_redirect off;
}
### Roundcube ###
location ^~ /roundcube/ {
client_max_body_size 1G;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
proxy_buffering on;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:83;
proxy_redirect off;
}
### SHELL ###
location ^~ /shellinabox/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#auth_basic "Restricted Area";
#auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:4200;
proxy_read_timeout 90;
}
location ^~ /wordpress/ {
client_max_body_size 1G;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
proxy_buffering on;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:84;
proxy_redirect off;
}
location ^~ /pihole {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:86/admin;
proxy_read_timeout 90;
}
}

Move the already existing nextcloud.conf to nextcloud.conf.bak and create a new one:

mv /etc/nginx/conf.d/nextcloud.conf /etc/nginx/conf.d/nextcloud.conf.bak
vi /etc/nginx/conf.d/nextcloud.conf

Paste all the following rows:

server {
server_name 127.0.0.1;
listen 127.0.0.1:82 default_server;
include /etc/nginx/proxy.conf;
root /var/www/nextcloud/;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
client_max_body_size 10240M;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ \.(?:flv|mp4|mov|m4a|m4v)$ {
mp4;
mp4_buffer_size 100m;
mp4_max_buffer_size 1024m;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache NEXTCLOUD;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
location ~ \.(?:css|js|woff|svg|gif|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
access_log off;
expires 365d;
}
}

Optionally: Roundcube

vi /etc/nginx/conf.d/roundcube.conf

Paste the following rows:

server {
server_name 127.0.0.1;
listen 127.0.0.1:83 default_server;
root /var/www/;
include /etc/nginx/proxy.conf;
client_max_body_size 1024M;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
charset utf-8;
location ^~ /roundcube {
index index.php;
location ~ ^/favicon.ico$ {
root /var/www/roundcube/skins/default/images;
log_not_found off;
access_log off;
expires max;
}
location ~ ^/roundcube/(README|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
deny all;
}
location ~ ^/roundcube/(bin|SQL|config|temp|logs)/ {
deny all;
}
location ~ /roundcube/\.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
fastcgi_index index.php;
try_files $uri =404;
}
location ~ /roundcube/\.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
}

Optionally: WordPress

vi /etc/nginx/conf.d/wordpress.conf

Paste the following rows:

server {
server_name 127.0.0.1;
listen 127.0.0.1:84 default_server;
include /etc/nginx/proxy.conf;
root /var/www/;
charset utf-8;
location ^~ /wordpress {
client_max_body_size 1024M;
index index.php;
access_log /var/log/nginx/wordpress.access.log main;
error_log /var/log/nginx/wordpress.error.log warn;
location /wordpress {
try_files $uri $uri/ /wordpress/index.php$args;
}
location = /wordpress/favicon.ico {
log_not_found off;
access_log off;
}
location = /wordpress/robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
fastcgi_index index.php;
}
location ~ /wordpress/\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location /blog/wp-admin {
allow 192.168.2.0/24;
deny all;
#auth_basic "Restricted Area";
#auth_basic_user_file /etc/nginx/.htpasswd;
}
location ~ ^/wordpress/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ {
deny all;
}
}
}

You have to modify the “/var/www/wordpress/wp-config.php” properly as well:

<?php
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
 $_SERVER['HTTPS']='on';
if(isset($_SERVER['HTTP_X_FORWARDED_HOST']))
 $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
define('WP_HOME', 'https://YOUR.DEDYN.IO/wordpress');
define('WP_SITEURL', 'https://YOUR.DEDYN.IO/wordpress');
define('DB_NAME', 'wpblog');
define('DB_USER', 'wp-db-user');
define('DB_PASSWORD', 'wp-db-pwd');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');
define('AUTH_KEY', '***');
define('SECURE_AUTH_KEY', '***');
define('LOGGED_IN_KEY', '***');
define('NONCE_KEY', '***');
define('AUTH_SALT', '***');
define('SECURE_AUTH_SALT', '***');
define('LOGGED_IN_SALT', '***');
define('NONCE_SALT', '***');
define('WP_REDIS_PATH', '/var/run/redis/redis.sock');
define('WP_CACHE_KEY_SALT', 'wblog_');
define('WP_CACHE', true);
define('WP_REDIS_PORT', '0');
define('WP_REDIS_DATABASE', '0');
define('WP_REDIS_SCHEME', 'unix');
$table_prefix = 'fs_';
define('WP_DEBUG', false);
if ( !defined('ABSPATH') )
 define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');

Your WordPress-Salts can be generated here.


Modify the Shellinabox configuration "SHELLINABOX_ARGS="...""
vi /etc/default/shellinabox

to

SHELLINABOX_ARGS="--no-beep --localhost-only --disable-ssl"

and restart shellinabox:

service shellinabox restart

Finally ammend the letsencrypt.conf: add “include /etc/nginx/proxy.conf;”

server {
listen 127.0.0.1:81 default_server;
server_name 127.0.0.1; 
include /etc/nginx/proxy.conf;
location ^~ /.well-known/acme-challenge {
default_type text/plain;
root /var/www/letsencrypt;
}
}

Now restart NGINX

service nginx restart

and enjoy your Nextcloud, Roundcube and WordPress behind a reverse proxy.


Carsten Rieger

21 Responses

  1. Robin says:

    Just one quastion, so I’m going to use the NextCloud setup as NGINX proxy also?
    I did not understand if I should use that installation or if I should start with a new one?

    • If you already set up all components (nginx, php, mysql, redis) you just have to change the conf-files (/etc/nginx/nginx.conf and /etc/ngninx/conf.d/*.conf).

      • Robin says:

        Ok, it should be nice to have a guide how to do this but in a stand a lone nginx server (VM)

        • Hhhmm…not sure if i got you right? Why do you prefer a reverse proxy configuration? Why do you need a new and dedicated guide? For most of all the Nextclouders the non-reverse proxy would be sufficient. Cheers, Carsten

          • Robin says:

            Hi,
            I want to have 3 things on my server wordpress, nextcloud and one other service over port 80.
            All of this services are on it’s own VM.
            So what I want is to run a NGINX reverseproxy on it’s own VM also so that VM can direct the req to the right service.
            I don’t like to mix many things in one and the same VM.

          • yes – no problem: configure the gateway.conf accordingly as shown here.
            instead of using 127.0.0.1: redirect to the other vm’s IP:.

          • Robin says:

            Thanks,
            But it’s still confusing, I think that many people want/can enjoy a guide in this matter.
            How to make a stand a lone NGINX proxy VM and re-direct the traffic to the Nextcloud VM that we have installed trough your guide.

            Then you can have for example test.com -> wordpress and also hi.com -> nextcloud over the same port and ip.
            It should be greate.

  2. vipernet says:

    Hi Carsten,

    I found the source of the endless redirection loop issue: it’s the
    location ^~ /nextcloud {
    rewrite ^ /nextcloud/index.php$uri;
    }
    This seems to create an redirection loop, if you want to access NC by domain.com/nextcloud

    Solution: cascade the check and the index.php redirection
    location ^~ /nextcloud {

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

    Bests!

  3. Edi says:

    Hallo Carsten,

    ich habe eine eigene Domain bei INWX und würde zu Hause meine Nextcloud über cloud.MeineDomain.net erreichbar machen.
    Später evtl. auch etwas anderes z.B. blog.MeineDomain.net.
    Sehe ich das richtig, dass ich dann anstatt der location-Sektion mehrere Server-Sektionen habe z.B.

    server {
    listen 443 ssl http2 default_server;
    server_name cloud.MeineDomain.net;

    location ^~ / {

    proxy_pass http://127.0.0.1:82;
    proxy_redirect off;
    }

    server {
    listen 443 ssl http2;
    server_name blog.MeineDomain.net;

    location ^~ / {

    proxy_pass http://127.0.0.1:83;
    proxy_redirect off;
    }

    usw.

    LG

    • Ja, genau. Aber Achtung: default_server nur einmal pro Port 😉
      server {
      listen 443 ssl http2 default_server;
      server_name cloud.MeineDomain.net;
      …}

      server {
      listen 443 ssl http2 default_server;
      server_name blog.MeineDomain.net;
      …}
      Servus, Carsten

  4. vipernet says:

    Hi Carsten, can you confirm that the subdirectory modification to https://domain.com/nextcloud does work?
    In nextcloud.error.log I get several “rewrite or internal redirection cycle when processing “/nextcloud/index.php/nextcloud/index.php/nextcloud/index.php/nextcloud/” … messages
    The browser returns error 500.

    I also changed “overwrite.cli.url” in config.php to ‘https://domain.com/nextcloud’; without further effect.
    Is there something else in config.php that has to be modified? (htaccess.RewriteBase, overwritewebroot, … ?)

    Bests

    • Hi, in general yes-i can confirm (except typos).
      I’m not at home and sporadically online only:
      Edit
      ‘overwrite.cli.url’ => ‘https://your.dedyn.io/nextcloud’,
      and if exists the overwrite.web… as well.

      Remove
      ‘htaccess.RewriteBase’ => ‘/’,

      Please compare your configs to Nextcloud 13 documentation and decatec. de as long as i am off. Apologize, Carsten

  5. Sergei says:

    Dear Carsten,

    Thank you for such a detailed, thorough and well-maintained guide. I wanted to ask you if you are aware of an existing nging bug that causes large dowloads to fail while using http2. There was a big discussion over at nextcloud forums and they advise to switchover to apache or disable http2. Do you know any other workaround, or maybe know how to proxy it to other webapp that can share large files (>30 gb), like Open MediaVault or something.

    Best Regards,

    • Hey Sergei, i am not aware of a known bug regarding to your description.
      But I can imagine that timeouts and/or buffers settings causes those interrupts of big downloads. Did you have a look in the proper logfiles (nginx, php, application) already.
      It depends on so many parameters: bandwith (upload), nginx configuration (loadbalancer, proxy, reverse proxy), server os, php version (I limited the maximum amount of data to 10G…and you?) and so on. Did you try to e.g. increase bodysizes, buffersizes, timeouts or chaches that are configured in my *.conf files. Please also verify the available storage on your server ;-).
      I would suggest to gather all these information and then i would raise a ticket at github.
      Cheers, Carsten

  6. vipernet says:

    Dear Carsten,

    thanks for the excellent guide.
    Do you think there is a possibility to access Nextcloud also through a subpath: YOUR.DEDYN.IO/nextcloud/

    I already tried modifying “location ^~ / {” to “location ^~ /nextcloud/ {” inside of gateway.conf, but it seemed to require further changes…

    Bests

    • Yes, for sure.

      ~~~ gateway.conf: ~~~
      location ^~ /nextcloud/ {
      client_max_body_size 10G;
      proxy_connect_timeout 3600;
      proxy_send_timeout 3600;
      proxy_read_timeout 3600;
      send_timeout 3600;
      proxy_buffering on;
      proxy_max_temp_file_size 10240m;
      proxy_request_buffering on;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://127.0.0.1:82;
      proxy_redirect off;
      }

      ~~~ nextcloud.conf: ~~~
      server {
      server_name 127.0.0.1;
      listen 127.0.0.1:82 default_server;
      include /etc/nginx/proxy.conf;
      root /var/www/;
      access_log /var/log/nginx/nextcloud.access.log main;
      error_log /var/log/nginx/nextcloud.error.log warn;
      location = /robots.txt {
      allow all;
      log_not_found off;
      access_log off;
      }
      location = /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
      }
      location = /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
      }
      client_max_body_size 10240M;
      location ^~ /nextcloud {
      rewrite ^ /nextcloud/index.php$uri;
      }
      location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)/ {
      deny all;
      }
      location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console) {
      deny all;
      }
      location ~ \.(?:flv|mp4|mov|m4a)$ {
      mp4;
      mp4_buffer_size 5m;
      mp4_max_buffer_size 10m;
      fastcgi_split_path_info ^(.+\.php)(/.*)$;
      include fastcgi_params;
      include php_optimization.conf;
      fastcgi_pass php-handler;
      fastcgi_param HTTPS on;
      }
      location ~ ^/nextcloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
      fastcgi_split_path_info ^(.+\.php)(/.*)$;
      include fastcgi_params;
      include php_optimization.conf;
      fastcgi_pass php-handler;
      fastcgi_param HTTPS on;
      }
      location ~ ^/nextcloud/(?:updater|ocs-provider)(?:$|/) {
      try_files $uri/ =404;
      index index.php;
      }
      location ~ \.(?:css|js|woff|svg|gif)$ {
      try_files $uri /index.php$uri$is_args$args;
      include /etc/nginx/proxy.conf;
      access_log off;
      expires 30d;
      }
      location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
      try_files $uri /index.php$uri$is_args$args;
      access_log off;
      expires 30d;
      }
      }

      Cheers, Carsten

  1. 23. February 2018

    […] Nextcloud 13, Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy […]

  2. 26. February 2018

    […] Nextcloud 13, Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy […]

  3. 26. February 2018

    […] Nextcloud 13, Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy […]

  4. 27. February 2018

    […] Nextcloud 13, Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy […]

Leave a Reply

Your email address will not be published. Required fields are marked *