Can't connect from external network because Nextcloud adds internal port number behind NGINX reverse proxy in the url

Nextcloud version: 27.1.1
Operating system and version: Debian GNU/Linux 11 (bullseye) aarch64
Apache or nginx version: nginx/1.18.0
PHP version: 8.2

The issue you are facing:
I am trying to connect to my nextcloud server from outside my network through a reverse proxy but the connection is failing because the url is being rewritten with the internal por used by nextcloud.
example: is redirected to and fails because port 3001 is not open on my router
I have tried port_in_redirect off; in location /nextcloud before proxy_pass;
Here’s my reverse proxy conf, please tell me what’s wrong with it, I really want this to work.

server {
    listen 80;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # Enforce https
    return 301 https://$server_name$request_uri;

server {
    listen 443 ssl http2;
    ssl_certificate     /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains;" always;

    root /var/www;

    # These are needed for most things to work through the proxy
    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;

    # Without this, every proxy request will timeout inexplicably
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_read_timeout 300;
    # For big files upload and download
    client_max_body_size 100G;
    client_body_timeout 259200s;
    client_body_temp_path /tmp/nginx-tmp 1 2;
    fastcgi_read_timeout 259200s;
    fastcgi_request_buffering off;
    proxy_buffering off;

    # Main page
    location / {

    # Nextcloud page
    location /nextcloud {
        port_in_redirect off;

    # Needed here for nextcloud to work, doesn't work if I leave it on the virtual host
    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in the Nextcloud `.htaccess` that concern `/.well-known`.

        location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /nextcloud/remote.php/dav/; }

        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /nextcloud/index.php$request_uri;

    # Git frontend page
    location /git/ {
        client_max_body_size 512M;
        # make nginx use unescaped URI, keep "%2F" as is
        rewrite ^ $request_uri;
        rewrite ^/git(/.*) $1 break;


and my nextcloud virtual host file:

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

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

server {
    listen 3001       ssl http2;
    #listen [::]:3001  ssl http2;

    # Path to the root of the domain
    root /var/www;

    # Use Mozilla's guidelines for SSL/TLS settings
    ssl_certificate     /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # Add .mjs as a file extension for javascript
    # Either include it in the default mime.types list
    # or include you can include that list explicitly and add the file extension
    # only for Nextcloud like below:
    include mime.types;
    types {
        text/javascript mjs;

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

    # .well-known rules used to be here but were moved to the reverse proxy config so they work again

    location ^~ /nextcloud {
        # set max upload size and increase upload timeout:
        client_max_body_size 100G;
        client_body_timeout 259200s;
        client_body_temp_path /tmp/nginx-tmp 1 2;
        fastcgi_read_timeout 259200s;
        fastcgi_request_buffering off;
        proxy_buffering off;
        # fastcgi_buffers 64 4K;

        # Enable gzip but do not remove ETag headers
        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 text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/ application/wasm 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;

        # Pagespeed is not supported by Nextcloud, so if your server is built
        # with the `ngx_pagespeed` module, uncomment this line to disable it.
        #pagespeed off;

        # The settings allows you to optimize the HTTP2 bandwitdth.
        # See
        # for tunning hints
        client_body_buffer_size 512k;

        # HTTP response headers borrowed from Nextcloud `.htaccess`
        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;

        # Remove X-Powered-By, which is an information leak
        fastcgi_hide_header X-Powered-By;

        # Specify how to handle directories -- specifying `/nextcloud/index.php$request_uri`
        # here as the fallback means that Nginx always exhibits the desired behaviour
        # when a client requests a path that corresponds to a directory that exists
        # on the server. In particular, if that directory contains an index.php file,
        # that file is correctly served; if it doesn't, then the request is passed to
        # the front-end controller. This consistent behaviour means that we don't need
        # to specify custom rules for certain paths (e.g. images and other assets,
        # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
        # `try_files $uri $uri/ /nextcloud/index.php$request_uri`
        # always provides the desired behaviour.
        index index.php index.html /nextcloud/index.php$request_uri;

        # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
        location = /nextcloud {
            if ( $http_user_agent ~ ^DavClnt ) {
                return 302 /nextcloud/remote.php/webdav/$is_args$args;

        # Rules borrowed from `.htaccess` to hide certain paths from clients
        location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)    { return 404; }
        location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console)                  { return 404; }

        # Ensure this block, which passes PHP files to the PHP process, is above the blocks
        # which handle static assets (as seen below). If this block is not declared first,
        # then Nginx will encounter an infinite rewriting loop when it prepends
        # `/nextcloud/index.php` to the URI, resulting in a HTTP 500 error response.
        location ~ \.php(?:$|/) {
            # Required for legacy support
            rewrite ^/nextcloud/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /nextcloud/index.php$request_uri;

            fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            set $path_info $fastcgi_path_info;

            try_files $fastcgi_script_name =404;

            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $path_info;
            fastcgi_param HTTPS on;

            fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
            fastcgi_param front_controller_active true;     # Enable pretty urls
            fastcgi_pass php-handler;

            fastcgi_intercept_errors on;
            fastcgi_request_buffering off;

            fastcgi_max_temp_file_size 0;

        # Serve static files
        location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
            try_files $uri /nextcloud/index.php$request_uri;
            add_header Cache-Control "public, max-age=15778463, $asset_immutable";
            access_log off;     # Optional: Don't log access to assets

            location ~ \.wasm$ {
                default_type application/wasm;

        location ~ \.woff2?$ {
            try_files $uri /nextcloud/index.php$request_uri;
            expires 7d;         # Cache-Control policy borrowed from `.htaccess`
            access_log off;     # Optional: Don't log access to assets

        # Rule borrowed from `.htaccess`
        location /nextcloud/remote {
            return 301 /nextcloud/remote.php$request_uri;

        location /nextcloud {
            try_files $uri $uri/ /nextcloud/index.php$request_uri;

Is this the first time you’ve seen this error?: Yes

Steps to replicate it:

  1. Set up an NGINX reverse proxy and add a /nextcloud location as the documentation shows
  2. Set up a Nextcloud virtual hosts that listens on any non-open internal port
  3. Try to access externally and watch as your url is rewritten to try and access the non-open port

The output of your Nextcloud log in Admin > Logging: I don’t think this is related, there seems to be an issue open about this log message.

Error	core	OC\User\NoUserException: Backends provided no user object

The output of your config.php file in /path/to/nextcloud (make sure you remove any identifiable information!):

$CONFIG = array (
  'instanceid' => 'removed',
  'passwordsalt' => 'removed',
  'secret' => 'removed',
  'trusted_domains' =>
  array (
    0 => '',
    1 => '',
    2 => '',
    3 => '',
  'trusted_proxies' =>
  array (
    0 => '',
    1 => '',
    2 => '',
    3 => '',
  'overwrite_protocol' => 'https',
  'overwrite_host' => '',
  'overwritewebroot' => '/nextcloud',
  'datadirectory' => '/mnt/ncdata',
  'dbtype' => 'mysql',
  'version' => '',
  'overwrite.cli.url' => '',
  'dbname' => 'nextcloud_db',
  'dbhost' => 'localhost',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'mysql.utf8mb4' => true,
  'dbuser' => 'oc_admin2',
  'dbpassword' => 'removed',
  'installed' => true,
  'maintenance' => false,
  'memcache.local' => '\\OC\\Memcache\\Redis',
  'memcache.distributed' => '\\OC\\Memcache\\Redis',
  'filelocking.enabled' => true,
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'redis' =>
  array (
    'host' => '/var/run/redis/redis-server.sock',
    'port' => 0,
    'timeout' => 0,
    'password' => '',
    'dbindex' => 0,
  'twofactor_enforced' => 'true',
  'twofactor_enforced_groups' =>
  array (
    0 => 'admin',
    1 => 'users',
  'twofactor_enforced_excluded_groups' =>
  array (
  'theme' => '',
  'loglevel' => 2,

The output of your Apache/nginx/system log in /var/log/____:
no logs are being generated about this issue (it’s all just normal local network traffic to nextcloud)

Well, for one some of your overwrite parameters are incorrectly specified:


Please restart php-fpm after changing these to be sure they’re active.

Thanks for catching that mistake
The issue solved itself overnight, however, before I even touched on what you pointed at
I guess whatever I did last when I gave up did the trick
Unluckily I didn’t document it, just messing around with the reverse-proxy configuration, so this will remain a mystery