Help Me Create A Reverse Proxy For Multiple Services Hosted On Local Machine :)

What I’m trying to do: Create a reverse proxy for multiple services (web servers, Nextcloud, etc.). Prior to configuring the reverse proxy, both the web server and Nextcloud were functioning. I am seeking to have the reverse proxy terminate TLS for the services and currently have only 443 whitelisted via the host FW.

Where I’m stuck: I have created and linked the /etc/nginx/sites-enabled/reverse proxy.conf config file within /etc/nginx/nginx.conf, and confirmed valid configuration via sudo nginx -s reload, but the browser states its inability to connect to the server.

What I’ve already tried: Below are my configuration files. Commented files/services are simply placeholders for future goals and not installed. Thank you for any help!

  1. nginx.conf
#----------------
# Documentation |
#----------------
# Directive directory   https://nginx.org/en/docs/dirindex.html
# Reverse proxy         https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
# Server                https://docs.nginx.com/nginx/admin-guide/web-server/web-server/

#-------
# Main |
#-------

# Defines worker processes' user + group credentials
user www-data;

# Quantity = CPU cores 
worker_processes 2;

# Location + logging level
error_log /var/log/nginx/error_main.log debug;

# Defines file containing main PID
pid /run/nginx.pid;

events {
        # Max simultaneous connections per worker process
        worker_connections      1024;
}

http {
        #-------
        # Logs |
        #-------

        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

        error_log       /var/log/nginx/error_http.log debug;

        # main applies pre-defined log_format
        access_log      /var/log/nginx/access_http.log main;

        #----------
        # SSL/TLS | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/
        #----------

        ssl_certificate         /etc/ssl/certs/name-net-selfsigned.crt;
        ssl_certificate_key     /etc/ssl/private/name-net-selfsigned.key;
        ssl_protocols           TLSv1.3;

        # Reuse in Nextcloud config
        add_header              Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        #-----------------------
        # SSL/TLS optimization | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/#optimize
        #-----------------------

        # 1m = 4k sessions
        ssl_session_cache       shared:SSL-TLS:1m;
        ssl_session_timeout     10m;

        #-------
        # MIME |
        #-------

        include         /etc/nginx/mime.types;
        default_type    application/octet-stream;

        #-----------------------------
        # File transfer optimization |
        #-----------------------------

        sendfile                on;

        # Provide client file w/out buffering. Improves static content transfer rate. Utilize w/ static content servers.
        tcp_nopush              off;

        # Limits data transer amount per sendfile() call. Prevents individual call completely seizing worker processes.
        sendfile_max_chunk      2m;

        #------------------------------
        # TCP connection optimization |
        #------------------------------

        # Low traffic site. Low value minimizes idle connections.
        keepalive_timeout       30;

        # Max requests per keepalive connection
        keepalive_requests      100;

        #------------
        # Nextcloud |
        #------------

        upstream php-handler {
                server unix:/var/run/php/php8.3-fpm.sock;
        }

        # Set the `immutable` cache control options only for assets with a cache busting `v` argument
        map $arg_v $asset_immutable {
                "" "";
                default ", immutable";
        }

        #----------------
        # Reverse proxy | Redifining request headers unnecessary. Proxied services located locally.
        #----------------
        include /etc/nginx/sites-enabled/reverse_proxy.conf;

        #-----------
        # Services |
        #-----------
        server {
                http2   on;

                include /etc/nginx/sites-enabled/charlie.conf;
                # include /etc/nginx/sites-enabled/sierra.conf;

                # include /etc/nginx/sites-enabled/gitlab.conf;

                include /etc/nginx/sites-enabled/nextcloud.conf;

                # include /etc/nginx/sites-enabled/vaultwarden.conf;
        }
        # include /etc/nginx/sites-enabled/jellyfin.conf;
        # include /etc/nginx/sites-enabled/collabora.conf;
}

  1. reverse_proxy.conf
server {
        listen  443 ssl;
        http2   on;

        #----------
        # Port 80 |
        #----------

        location /charlie {
                proxy_pass http://localhost:80/charlie;

                #-----------
                # Security |
                #-----------

                allow   192.168.1.0/24;
                deny    all;
        }

        #location /sierra {
                # proxy_pass http://localhost:80/sierra;
        #}

        #location /gitlab {
                # proxy_pass http://localhost:80/gitlab;
        #}

        #location /nextcloud {
                # proxy_pass http://localhost:80/nextcloud;
        #}

        #location /vaultwarden {
                # proxy_pass http://localhost:80/vaultwarden;
        #}

        #-------------------
        # Port 8096 + 9980 |
        #-------------------

        #location /jellyfin {
                # proxy_pass http://localhost:8096;
        #}

        #location /collabora {
                # proxy_pass http://localhost:9980;
        #}
}

  1. charlie.conf (web server)
location /charlie {
        root            /var/www/html;
        index           index.html;

        error_log       /var/log/nginx/error_charlie.log debug;

        # main parameter applies pre-defined config log_format
        access_log      /var/log/nginx/access_charlie.log main;

        # Improves static content transfer rate via buffer bypass
        tcp_nopush      on;
}

1 Like

Hey @Swimmer2-Unboxed7! I don’t really have the bandwidth to fully replicate your environment, but I’ve put together a very simple snippet that works fine in this codepen. I would suggest you take this as a starting point and slowly try to add directives until either everything works as intended or you run into the directive that’s causing your servers to not be reachable.

2 Likes

So I changed the proxy_pass and listen port to 81 as you recommended, and it worked for the web server? Why is that 80 fails, but 81 works?

After this, I created an additional server block for Nextcloud and set listen to 82 and created an additional location block within the reverse proxy server and set proxy_pass to 82 as well. This however, did not work.

So as of now the reverse proxy functions for a single web server, but not Nextcloud.

The ports there are for the codepen example. You should be able to use any ports you have available in your system. If you are using the exact example I shared and it’s not working, the issue is likely with port 82 being already in use by something else in your system or NextCloud not being reachable at all.

2 Likes

I’ve noticed that I missed a section of Nextcloud documentation regarding reverse proxies. I am currently implementing this in /var/www/nextcloud/config/config.php.

This is my current configuration. It currently results in the connection timing out after attempting to load for minutes.

  1. nginx.conf
#----------------
# Documentation |
#----------------
# Directive directory   https://nginx.org/en/docs/dirindex.html
# Reverse proxy         https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
# Server                https://docs.nginx.com/nginx/admin-guide/web-server/web-server/

#-------
# Main |
#-------

# Defines worker processes' user + group credentials
user www-data;

# Quantity = CPU cores 
worker_processes 2;

# Location + logging level
error_log /var/log/nginx/error_main.log debug;

# Defines file containing main PID
pid /run/nginx.pid;

events {
        # Max simultaneous connections per worker process
        worker_connections      1024;
}

http {
        #-------
        # Logs |
        #-------

        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

        error_log       /var/log/nginx/error_http.log debug;

        # main applies pre-defined log_format
access_log      /var/log/nginx/access_http.log main;

        #----------
        # SSL/TLS | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/
        #----------

        ssl_certificate         /etc/ssl/certs/oller-net-selfsigned.crt;
        ssl_certificate_key     /etc/ssl/private/oller-net-selfsigned.key;
        ssl_protocols           TLSv1.3;

        # Reuse in Nextcloud config
        add_header              Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        #-----------------------
        # SSL/TLS optimization | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/#optimize
        #-----------------------

        # 1m = 4k sessions
        ssl_session_cache       shared:SSL-TLS:1m;
        ssl_session_timeout     10m;

        #-------
        # MIME |
        #-------

        include         /etc/nginx/mime.types;
        default_type    application/octet-stream;

        #-----------------------------
        # File transfer optimization |
        #-----------------------------

        sendfile                on;

        # Provide client file w/out buffering. Improves static content transfer rate. Utilize w/ static content servers.
        tcp_nopush              off;

        # Limits data transer amount per sendfile() call. Prevents individual call completely seizing worker processes.
        sendfile_max_chunk      2m;

        #------------------------------
        # TCP connection optimization |
        #------------------------------

        # Low traffic site. Low value minimizes idle connections.
        keepalive_timeout       30;

        # Max requests per keepalive connection
        keepalive_requests      100;

        #------------
        # Nextcloud |
        #------------

        upstream php-handler {
                server unix:/var/run/php/php8.3-fpm.sock;
        }

        # Set the `immutable` cache control options only for assets with a cache busting `v` argument
        map $arg_v $asset_immutable {
                "" "";
                default ", immutable";
        }

        #----------------
        # Reverse proxy | Redifining request headers unnecessary. Proxied services located locally.
        #----------------
        #include /etc/nginx/sites-enabled/reverse_proxy.conf;

        server {
                listen  443 ssl;
                http2   on;

                location /charlie {
                        allow   192.168.1.0/24;
                        deny    all;

                        proxy_pass http://localhost:81;
                }
                location /nextcloud {
                        allow   192.168.1.0/24;
                        deny    all;

                        proxy_pass http://localhost:82;

                        proxy_set_header        Host $host;
                        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 $scheme;

                        add_header              Front-End-Https on;
                }
                location /.well-known/carddav {
                        allow   192.168.1.0/24;
                        deny    all;

                        return 301 $scheme://$host/remote.php/dav;
                }
                location /.well-known/caldav {
                        allow   192.168.1.0/24;
                        deny    all;

                        return 301 $scheme://$host/remote.php/dav;
                }
                location ^~ /.well-known {
                        allow   192.168.1.0/24;
                        deny    all;

                        return 301 $scheme://$host/index.php$uri;
                }
        }

        #-------------------
 # Proxied services |
        #-------------------

        server {
                listen  127.0.0.1:81;
                http2   on;

                include /etc/nginx/sites-available/charlie.conf;
        }
        server {
                listen  127.0.0.1:82;
                http2   on;

                include /etc/nginx/sites-enabled/nextcloud.conf;
        }

        #-----------
        # Services |
        #-----------
        #server {
        #       listen  443 ssl;
        #       http2   on;

                #include /etc/nginx/sites-enabled/charlie.conf;
                # include /etc/nginx/sites-enabled/sierra.conf;

                # include /etc/nginx/sites-enabled/gitlab.conf;

        #       include /etc/nginx/sites-enabled/nextcloud.conf;

                # include /etc/nginx/sites-enabled/vaultwarden.conf;
        #}
        # include /etc/nginx/sites-enabled/jellyfin.conf;
        # include /etc/nginx/sites-enabled/collabora.conf;
}

  1. config.php (Nextcloud)
<?php
$CONFIG = array (
  'passwordsalt' => '',
  'secret' => '',
  #---------    
  # Access |
  #---------
  'trusted_domains' =>
  array (
    0 => 'localhost:82',
  ),
  'allowed_admin_ranges' =>
  array (
    0 => '127.0.0.1/8',
    1 => '192.168.1.145/24',
  ),
  'twofactor_enforced' => 'true',
  'twofactor_enforced_groups' =>
  array (
  ),
  'twofactor_enforced_excluded_groups' =>
  array (
  ),
  #----------------
  # Reverse proxy | https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html#example
  #----------------
  'trusted_proxies' => ['localhost'],                      
  'overwritehost' => 'optiplex:82',                   # Proxy hostname + port
  'overwriteprotocol' => 'https',                       # Proxy protocol (HTTP/HTTPS)
  'overwritewebroot' => '',                             # ?
  'overwritecondaddr' => '',                            # ?
  'overwrite.cli.url' => 'http://localhost:82',            # ?
  #-------
  # Misc |
  #-------
  'version' => '31.0.4.1',
  'default_phone_region' => 'US',
  'maintenance_window_start' => 1,
  #-----------
  # Database |
  #-----------
  'datadirectory' => '/var/www/nextcloud/data',
  'dbtype' => 'mysql',
  'dbname' => 'nc_db',
  'dbhost' => 'localhost',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'mysql.utf8mb4' => true,
  'dbuser' => 'nc_user',
  'dbpassword' => '',
  'installed' => true,
  'instanceid' => '',
  #--------
  # Redis | https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/caching_configuration.html#
  #--------
  'redis' =>
  array (
    'host' => '/run/redis/redis-server.sock',
    'port' => 0,
    'timeout' => 0.0,
    'password' => '',
  ),
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'maintenance' => false,
  #-------
  # Mail |
  #-------
  'mail_smtpmode' => 'smtp',
  'mail_smtpauth' => true,
  'mail_sendmailmode' => 'smtp',
  'mail_smtpname' => '',
  'mail_smtppassword' => '',
);

The only suggestion I have re your NGINX config at this point is to move your SSL config to inside your server block instead of your http block. I also see that you have added things such as allow and deny statements before testing your config works. I will again suggest you start with a fresh totally new config and slowly add directives and test things work before diving into creating a more complex config.

Beyond that, I think you might want to ask in a NextCloud community; if you are timing out it means the service (NextCloud) is not reachable, and I am not even remotely knowledgable with the tool nor is this the best community to get help with it.

Hi @Swimmer2-Unboxed7 .

I assume you’ve looked through our Reverse Proxy docs .

if there’s something that we could add to that doc to accommodate services like Nextcloud, we’d love to see a pull request.

We’ve tried to make the process easier by including an “Edit this page” link at the bottom of every doc page. I’m wondering if there’s some setting for (maybe) proxy_pass that we could add to our docs.

1 Like