HAProxy, NGINX und Nextcloud interal Servererror

Hello,
I am trying to run Nextcloud with NGINX behind a HAProxy reverseproxy. There I now get an internal server error on the loginpage of nextcloud. Ther is the current session ID shown, but no remote address. Currently I am running it on a Raspberry Pi and localhost. Later it will be extended.

Hardware : Raspberry PI4B+ 4GB
Networkinfrastructure: Fritzbox7490 (Router)>Switch (TL-SG108E)>Raspi

Software:
Raspian (Version 10 Buster, Kerne 5.4.51-v7l+)
Nextcloud (19.0.0.2)
NGINX (1.14.2)
HAProxy (1.8.19-1+rpi1)
PHP7.3
MariaDB 10.3.23

Following the errors from the Nextcloud logfile:

{“reqId”:“baOWTv94XsSXJI8VUehv”,“level”:3,“time”:“2020-09-19T09:36:30+02:00”,“remoteAddr”:“”,“user”:“–”,“app”:“PHP”,“method”:“GET”,“url”:“/nextcloud/login”,“message”:“Uninitialized string offset: 0 at /var/www/nextcloud/lib/private/Security/Normalizer/IpAddress.php#76”,“userAgent”:“Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0”,“version”:“19.0.2.2”}

and

“reqId”:“baOWTv94XsSXJI8VUehv”,“level”:3,“time”:“2020-09-19T09:36:30+02:00”,“remoteAddr”:“”,“user”:“–”,“app”:“index”,“method”:“GET”,“url”:“/nextcloud/login”,“message”:{“Exception”:“Exception”,“Message”:“inet_ntop() expects parameter 1 to be string, bool given”,“Code”:0,“Trace”:[{“file”:“/var/www/nextcloud/lib/private/AppFramework/App.php”,“line”:137,“function”:“dispatch”,“class”:“OC\AppFramework\Http\Dispatcher”,“type”:“->”,“args”:[{“ class ”:“OC\Core\Controller\LoginController”},“showLoginForm”]},{“file”:“/var/www/nextcloud/lib/private/AppFramework/Routing/RouteActionHandler.php”,“line”:47,“function”:“main”,“class”:“OC\AppFramework\App”,“type”:“::”,“args”:[“OC\Core\Controller\LoginController”,“showLoginForm”,{“ class ”:“OC\AppFramework\DependencyInjection\DIContainer”},{“_route”:“core.login.showLoginForm”}]},{“function”:“__invoke”,“class”:“OC\AppFramework\Routing\RouteActionHandler”,“type”:“->”,“args”:[{“_route”:“core.login.showLoginForm”}]},{“file”:“/var/www/nextcloud/lib/private/Route/Router.php”,“line”:297,“function”:“call_user_func”,“args”:[{“ class ”:“OC\AppFramework\Routing\RouteActionHandler”},{“_route”:“core.login.showLoginForm”}]},{“file”:“/var/www/nextcloud/lib/base.php”,“line”:1012,“function”:“match”,“class”:“OC\Route\Router”,“type”:“->”,“args”:[“/login”]},{“file”:“/var/www/nextcloud/index.php”,“line”:37,“function”:“handleRequest”,“class”:“OC”,“type”:“::”,“args”:}],“File”:“/var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php”,“Line”:110,“Previous”:{“Exception”:“TypeError”,“Message”:“inet_ntop() expects parameter 1 to be string, bool given”,“Code”:0,“Trace”:[{“file”:“/var/www/nextcloud/lib/private/Security/Normalizer/IpAddress.php”,“line”:91,“function”:“inet_ntop”,“args”:[false]},{“file”:“/var/www/nextcloud/lib/private/Security/Normalizer/IpAddress.php”,“line”:108,“function”:“getIPv6Subnet”,“class”:“OC\Security\Normalizer\IpAddress”,“type”:“->”,“args”:[“”,128]},{“file”:“/var/www/nextcloud/lib/private/Security/Bruteforce/Throttler.php”,“line”:223,“function”:“getSubnet”,“class”:“OC\Security\Normalizer\IpAddress”,“type”:“->”,“args”:},{“file”:“/var/www/nextcloud/core/Controller/LoginController.php”,“line”:184,“function”:“getDelay”,“class”:“OC\Security\Bruteforce\Throttler”,“type”:“->”,“args”:[“”]},{“file”:“/var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php”,“line”:170,“function”:“showLoginForm”,“class”:“OC\Core\Controller\LoginController”,“type”:“->”,“args”:[null,null]},{“file”:“/var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php”,“line”:100,“function”:“executeController”,“class”:“OC\AppFramework\Http\Dispatcher”,“type”:“->”,“args”:[{“ class ”:“OC\Core\Controller\LoginController”},“showLoginForm”]},{“file”:“/var/www/nextcloud/lib/private/AppFramework/App.php”,“line”:137,“function”:“dispatch”,“class”:“OC\AppFramework\Http\Dispatcher”,“type”:“->”,“args”:[{“ class ”:“OC\Core\Controller\LoginController”},“showLoginForm”]},{“file”:“/var/www/nextcloud/lib/private/AppFramework/Routing/RouteActionHandler.php”,“line”:47,“function”:“main”,“class”:“OC\AppFramework\App”,“type”:“::”,“args”:[“OC\Core\Controller\LoginController”,“showLoginForm”,{“ class ”:“OC\AppFramework\DependencyInjection\DIContainer”},{“_route”:“core.login.showLoginForm”}]},{“function”:“__invoke”,“class”:“OC\AppFramework\Routing\RouteActionHandler”,“type”:“->”,“args”:[{“_route”:“core.login.showLoginForm”}]},{“file”:“/var/www/nextcloud/lib/private/Route/Router.php”,“line”:297,“function”:“call_user_func”,“args”:[{“ class ”:“OC\AppFramework\Routing\RouteActionHandler”},{“_route”:“core.login.showLoginForm”}]},{“file”:“/var/www/nextcloud/lib/base.php”,“line”:1012,“function”:“match”,“class”:“OC\Route\Router”,“type”:“->”,“args”:[“/login”]},{“file”:“/var/www/nextcloud/index.php”,“line”:37,“function”:“handleRequest”,“class”:“OC”,“type”:“::”,“args”:}],“File”:“/var/www/nextcloud/lib/private/Security/Normalizer/IpAddress.php”,“Line”:91},“CustomMessage”:“–”},“userAgent”:“Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0”,“version”:“19.0.2.2”}

The first error leads to the file /var/www/nextcloud/lib/private/Security/Normalizer/IpAddress.php#76, line 76. Following the lines from 75 to the end of the function.

private function getIPv6Subnet(string $ip, int $maskBits = 48): string {
        if ($ip[0] === '[' && $ip[-1] === ']') { // If IP is with brackets, for example [::1]
                $ip = substr($ip, 1, strlen($ip) - 2);
        }
        $pos = strpos($ip, '%'); // if there is an explicit interface added to the IP, e.g. fe80::ae2d:d1e7:fe1e:9a8d%enp2s0
        if ($pos !== false) {
                $ip = substr($ip, 0, $pos-1);
        }
        $binary = \inet_pton($ip);
        for ($i = 128; $i > $maskBits; $i -= 8) {
                $j = \intdiv($i, 8) - 1;
                $k = (int) \min(8, $i - $maskBits);
                $mask = (0xff - ((2 ** $k) - 1));
                $int = \unpack('C', $binary[$j]);
                $binary[$j] = \pack('C', $int[1] & $mask);
        }
        return \inet_ntop($binary).'/'.$maskBits;
}

Nextcloud config.php:

$CONFIG = array (
‘instanceid’ => ‘oc5ei17kv657’,
‘passwordsalt’ => ‘yVuG1xYKsjPDCzJILiBp9BFeEZmNe0’,
‘secret’ => ‘Eh7lNgKxuhoGzbyHD/gpMgDRjHkwfJptKQWSLE/D3FmPa75W’,
‘trusted_domains’ =>
array (
0 => ‘jcb.spdns.de’,
1 => ‘192.168.38.2’,
2 => ‘127.0.0.1’,
),
‘trusted_proxies’ =>
array (
0 => ‘localhost’,
1 => ‘127.0.0.1’,
2 => ‘192.168.38.1/24’,
),
‘datadirectory’ => ‘/var/nextcloud_data/’,
‘dbtype’ => ‘mysql’,
‘version’ => ‘19.0.2.2’,
‘overwrite.cli.url’ => ‘https://jcb.spdns.de/nextcloud’,
‘dbname’ => ‘mydbname’,
‘dbhost’ => ‘localhost’,
‘dbport’ => ‘’,
‘dbtableprefix’ => ‘oc_’,
‘mysql.utf8mb4’ => true,
‘dbuser’ => ‘mydbuser’,
‘dbpassword’ => ‘mydbpasspword’,
‘installed’ => true,
‘mail_smtpmode’ => ‘smtp’,
‘mail_smtpsecure’ => ‘ssl’,
‘mail_sendmailmode’ => ‘smtp’,
‘mail_from_address’ => ‘mailuser’,
‘mail_domain’ => ‘mymaildomain’,
‘mail_smtpauthtype’ => ‘LOGIN’,
‘mail_smtpauth’ => 1,
‘mail_smtphost’ => ‘mymailserver@mail.de’,
‘mail_smtpport’ => ‘465’,
‘mail_smtpname’ => ‘mymailadresse@mail.de’,
‘mail_smtppassword’ => ‘mymailpassword’,
‘memcache.local’ => ‘\OC\Memcache\APCu’,
‘overwriteprotocol’ => ‘https’,
‘logtimezone’ => ‘Europe/Berlin’,

);

NGINX Configuration:

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

server {
listen 127.0.0.1:82 ssl http2;
listen [::]:82 ssl http2;
server_name localhost;

    # Configure SSL
    #
    ssl on;

    # Certificates used
    ssl_certificate /etc/letsencrypt/jcb.spdns.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/jcb.spdns.de/key.pem;

    # Not using TLSv1 will break:
    #       Android <= 4.4.40
    #       IE <= 10
    #       IE mobile <=10


    # Removing TLSv1.1 breaks nothing else!
    # There are not many clients using TLSv1.3 so far, but this can be activated with nginx v1.13
    ssl_protocols TLSv1.2 TLSv1.3;

    # Using the recommended cipher suite from: https://wiki.mozilla.org/Security/Server_Side_TLS
    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';


    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/dhparams/dhparams.pem;

    # Specifies a curve for ECDHE ciphers.
    # High security, but will not work with Chrome:
    #ssl_ecdh_curve secp521r1;
    # Works with Windows (Mobile), but not with Android (DavDroid):
    #ssl_ecdh_curve secp384r1;
    # Works with Android (DavDroid):
    ssl_ecdh_curve prime256v1;

    # Server should determine the ciphers, not the client
    ssl_prefer_server_ciphers on;

    # OCSP Stapling
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/jcb.spdns.de/fullchain.pem;
    resolver 192.168.38.1;

    # SSL session handling
    ssl_session_timeout 24h;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;


    # Add headers to serve security related headers
    #
    # HSTS (ngx_http_headers_module is required)
    # In order to be recoginzed by SSL test, there must be an index.hmtl in the server's root
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    # Usually this should be "DENY", but when hosting sites using frames, it has to be "SAMEORIGIN"
    add_header Referrer-Policy "same-origin" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;


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

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

# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /nextcloud/public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /nextcloud/public.php?service=host-meta-json last;

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

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

location /.well-known/acme-challenge { }

location ^~ /nextcloud {
    # set max upload size
    client_max_body_size 10G;
    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 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;

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

    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 ~ ^/nextcloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
        include fastcgi_params;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
                    #Avoid sending the security headers twice
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;

        # Raise timeout values.
        # This is especially important when the Nextcloud setup runs into timeouts (504 gateway errors)
                    fastcgi_read_timeout 600;
                    fastcgi_send_timeout 600;
                    fastcgi_connect_timeout 600;
        fastcgi_request_buffering off;

        # Pass PHP variables directly to PHP.
        # This is usually done in the php.ini. For more flexibility, these variables are configured in the nginx config.
                    # All the PHP parameters have to be set in one fastcgi_param. When using more 'fastcgi_param PHP_VALUE' directives, the last one will override all the others.
        fastcgi_param PHP_VALUE "open_basedir=/var/www:/tmp/:/var/nextcloud_data:/dev/urandom:/proc/meminfo
                            upload_max_filesize = 10G
                            post_max_size = 10G
                            max_execution_time = 3600
                            output_buffering = off";

        # Make sure that the real IP of the remote host is passed to PHP.
        fastcgi_param REMOTE_ADDR $http_x_real_ip;
    }

    location ~ ^/nextloud/(?:updater|ocs-provider)(?:$|/) {
        try_files $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 /nextcloud/index.php$uri$is_args$args;
        proxy_set_header Cache-Control "public, max-age=7200";
        # Add headers to serve security related headers
        # Again use 'proxy_set_header' (not 'add_header') as the headers have to be passed through a proxy.
        proxy_set_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
        proxy_set_header X-Content-Type-Options nosniff;
        #proxy_set_header X-Frame-Options "SAMEORIGIN";
        proxy_set_header X-XSS-Protection "1; mode=block";
        proxy_set_header X-Robots-Tag none;
        proxy_set_header X-Download-Options noopen;
        proxy_set_header X-Permitted-Cross-Domain-Policies none;
        # Optional: Don't log access to assets
        access_log off;
    }

    location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
        try_files $uri /nextcloud/index.php$uri$is_args$args;
        # Optional: Don't log access to other assets
        access_log off;
    }
}

}

HAProxy Configuration:

global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon

     # Default SSL material locations
     ##ca-base /etc/ssl/certs
     ##crt-base /etc/ssl/private

     # Default ciphers to use on SSL-enabled listening sockets.
     # For more information, see ciphers(1SSL). This list is from:
     #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
     # An alternative list with additional directives can be obtained from
     #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
     ##ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCMRSA+AES:!aNULL:!MD5:!DSS
     ##ssl-default-bind-options no-sslv3

defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http

frontend http-in
bind :80
mode http
option httplog

     acl is_letsencrypt path -i -m beg /.well-known/acmechallange

     use_backend be_letsencrypt if is_letsencrypt
     redirect scheme https code 301 if !{ ssl_fc }

frontend https_in
bind *:443
mode tcp
option tcplog
option forwardfor

     acl tls req.ssl_hello_type 1

     tcp-request inspect-delay 5s
     tcp-request content accept if tls

     acl is_nextcloud req.ssl_sni -i jcb.spdns.de

     use_backend be_nextcloud if is_nextcloud

backend be_letsencrypt
mode http
server localhost 127.0.0.1:81

backend be_nextcloud
mode tcp
option ssl-hello-chk
server localhost 127.0.0.1:82

My current fallback setup with NGINX as a Reverseproxy works fine and I do not experience anyproblems. Maybe someone in here has got an idea where my mistake within the configuration is. I assume it has got something to with an IP-Address not beiing forwarded or so.

Best regards
Krischan

Hi,
found the error within the nginx config.

    # Make sure that the real IP of the remote host is passed to PHP.
    fastcgi_param REMOTE_ADDR $http_x_real_ip;

That line looks for the real IP whithin an nginx frontend, which I do not use any more.

Krischan

I also encountered this problem, thanks

Hi,
it would be helpful, if you post your error message. Within a standard installation it is in the installation directory.
Furthermore your webserver configuration might be required for better support, as well as the haproxy configuration.

Best regards