Troubleshooting Nginx Closed Connection Issues

kvm-virtualizationnginxssl

I 'm getting a lot of lines like these in the error log:

[info] 7521#7521: *1061 peer closed connection in SSL handshake while SSL handshaking, client: 198.41.231.201, server: 0.0.0.0:443
[info] 7521#7521: *1063 client closed connection while waiting for request, client: 198.41.231.201, server: 0.0.0.0:443
[info] 7522#7522: *1369 client prematurely closed connection while sending response to client
[info] SSL_write() failed (104: Connection reset by peer) while sending response to client

As you can see it's a "[info]" so i don't know if it's really a problem, but since yesterday my web server was returning errors, i don't know which errors exactly, the cloudflare says "Web server is returning an unknown error", and sometimes it returns "SSL handshake failed".

These errors started showing yesterday, but it happens quit frequently (each ~7-10days), i would think that it's a network problem at the host, but they say that the network is fine… So i'm kinda lost here.

I Searched about these errors in the google, but everyone that got this error was using nginx as reverse proxy, and i'm not.

Does someone know how can i fix it? Any help is welcome.

This is my nginx.conf:

load_module modules/ngx_http_modsecurity_module.so;

user nginx;

worker_processes auto;
#worker_rlimit_nofile    65535;
error_log               /var/log/nginx/error.log debug;
pid                     /var/run/nginx.pid;

events {
    worker_connections  1000;
    use                 epoll;
    multi_accept        on;

}

http {
    limit_req_zone $http_x_forwarded_for zone=limit_req:10m rate=80r/s;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsec/main.conf;

    client_header_timeout 60s;
    client_body_timeout 60s;
    client_max_body_size 2m;
    client_header_buffer_size 4k;
    client_body_buffer_size 1600k;
    large_client_header_buffers 2 2k;

    send_timeout 60s;
    keepalive_timeout 15 15;
    reset_timedout_connection       on;
    server_names_hash_max_size 1024;
    server_names_hash_bucket_size 1024;
    ignore_invalid_headers on;
    connection_pool_size 256;
    request_pool_size 4k;
    output_buffers 4 32k;
    postpone_output 1460;

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

    # Compression gzip
    gzip on;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";
    gzip_proxied any;
    gzip_min_length 256;
    gzip_comp_level 6;
    gzip_buffers 32 16k;
    gzip_types text/plain text/xml text/css text/js application/x-javascript application/xml image/png image/x-icon image/gif image/jpeg image/svg+xml application/xml+rss text/javascript application/atom+xml application/javascript application/json application/x-font-ttf font/opentype;

    open_file_cache_valid 120s;
    open_file_cache_min_uses 2;
    open_file_cache_errors off;
    open_file_cache max=5000 inactive=30s;
    open_log_file_cache max=1024 inactive=30s min_uses=2;

    # Php cache
    fastcgi_cache_path /var/cache/fastcgi levels=1:2 keys_zone=phpcache:100m inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_ignore_headers X-Accel-Expires Expires Cache-Control;

    # SSL Settings
    ssl_certificate         /etc/nginx/ssl/cf_cert.pem;
    ssl_certificate_key     /etc/nginx/ssl/cf_key.pem;
    ssl_client_certificate /etc/nginx/ssl/origin-pull-ca.pem;
    ssl_verify_client on;
    ssl_verify_depth 5;

    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 1h;
    ssl_protocols       TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA!RC4:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS";
    ssl_session_tickets on;
    ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_ecdh_curve secp384r1;
    ssl_buffer_size 4k;

    # Logs
    log_format  main    '$remote_addr - $remote_user [$time_local] $request '
                        '"$status" $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
    log_format  bytes   '$body_bytes_sent';
    #access_log          /var/log/nginx/access.log main;
    access_log off;

    # Cache bypass
    map $http_cookie $no_cache {
        default 0;
        ~SESS 1;
        ~wordpress_logged_in 1;
    }

    # Include additional configuration
    include /etc/nginx/cloudflare.inc;

    etag off;
    server_tokens off;

    # Headers
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Frame-Options deny always;

    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        listen 443 ssl http2; 
        server_name domain.com;

        root /home/user/domain/public;
        index index.php index.html;

        access_log /var/log/domain/domain.com.bytes bytes;
        access_log /var/log/domain/domain.com.log combined buffer=64k flush=3m;
        error_log /var/log/domain/domain.com.error.log info;

        underscores_in_headers on;

        include /etc/nginx/alias.conf;

        location / {
            include /etc/nginx/url_rewrite.conf;  

            location ~ [^/]\.php(/|$) {
                try_files $uri =404;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass    unix:/var/run/php-fpm.sock;
                fastcgi_index   index.php;
                include         /etc/nginx/fastcgi_params;
                fastcgi_buffering off;
                fastcgi_cache phpcache;
                fastcgi_cache_valid 200 60m;
                fastcgi_cache_methods GET;
                limit_req zone=limit_req burst=2;
                limit_req_status 429;
            }
        }

        location ~ /\. {access_log off; deny all; return 404;}
        disable_symlinks if_not_owner from=/home/user/domain/public;
    }
}

Best Answer

I doubt these are connection problems, since the client closed the connection in a clean way. It is more probable a portscanner is checking what hides behind port 443 (he might be surprised :-) ).

You can obtain a similar effect with:

telnet example.com https < /dev/null
openssl s_client -connect example.com:https < /dev/null
openssl s_client -connect example.com:https <<EOF
GET / HTTP/1.1
Host: example.com

EOF

Edit: if you are not running on port 443, the behaviour of the port scanner is more understandable:

  • it connects to the port and waits for a server banner (which is sent by an SMTP, IMAP, SSH and other types of servers). After a timeout it disconnects.
  • it connects to the port, performs a TLS handshake and waits for a server banner (which is sent by the TLS versions of the previous protocols). After a timeout it disconnects.
  • it tries to send an HTTP request. Since it is not interested in the page it disconnects and deduces that you are running an HTTP server.