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


Nextcloud & reverse Proxy

This reverse proxy configuration ist verified by Nextcloud, AMPLIFY and QUALYS SSL LABS:  no issues, warnings or errors were found.

Please substitute the red marked values (YOUR.DEDYN.IO and 192.168.2.x) only.


If you are interested in running Nextcloud in parallel with Roundcube, WordPress, Shellinabox and Pi-hole 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). This configuration leads to an A+ ranking and all Nextcloud checks will be successfully passed. 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 {
proxy_headers_hash_bucket_size 64;
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 your.dedyn.io;
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 your.dedyn.io;
include /etc/nginx/ssl.conf;
include /etc/nginx/header.conf;
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-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:82;
proxy_redirect off;
}
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-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:83;
proxy_redirect off;
}
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 ^~ /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;
proxy_pass http://127.0.0.1:85;
proxy_read_timeout 90;
}
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/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 / {
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)$ {
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 ~ ^/(?: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 ~ ^/(?: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;
}
}

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;
include /etc/nginx/proxy.conf;
root /var/www/;
client_max_body_size 1024M;
access_log /var/log/nginx/roundcube.access.log main;
error_log /var/log/nginx/roundcube.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', 'wpdbuser');
define('DB_PASSWORD', 'wpdbpwd');
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.


Optionally: Shellinabox

vi /etc/nginx/conf.d/shellinabox.conf

Paste the following rows:

server {
listen 85;
server_name 127.0.0.1:85 default_server; 
include /etc/nginx/proxy.conf;
access_log /var/log/nginx/shellinabox.access.log main;
error_log /var/log/nginx/shellinabox.error.log warn;
location /shellinabox/ {
rewrite ^/shellinabox/(.*) /$1 break;
#auth_basic "Restricted Area";
#auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:4200;
proxy_read_timeout 90;
}
}

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.


vi /etc/nginx/header.conf
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "same-origin" always;

vi /etc/nginx/optimization.conf
fastcgi_buffers 64 64K;
fastcgi_buffer_size 256k;
fastcgi_busy_buffers_size 3840K;
fastcgi_cache_key $http_cookie$request_method$host$request_uri;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
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;
gzip_disable "MSIE [1-6]\.";

vi /etc/nginx/php_optimization.conf
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_cache_valid 404 1m;
fastcgi_cache_valid any 1h;
fastcgi_cache_methods GET HEAD;

vi /etc/nginx/proxy.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_redirect off;

vi /etc/nginx/ssl.conf
ssl_certificate /etc/letsencrypt/live/your.dedyn.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.dedyn.io/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/your.dedyn.io/fullchain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK:!AES128';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
ssl_stapling on;
ssl_stapling_verify on;

Carsten Rieger

1 Response

  1. 23. 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 *