HTTPS connection refused after redirect on my Nginx server

I’m unable to get to my web server via HTTPS. If I try and connect on port 80 the connection is redirected to port 443 as a quick wget shows:

--2021-01-04 22:45:51--
Resolving corballis.co.uk (corballis.co.uk)... 83.86.93.178
Connecting to corballis.co.uk (corballis.co.uk)|83.86.93.178|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: [following]
--2021-01-04 22:45:52--
Connecting to corballis.co.uk (corballis.co.uk)|83.86.93.178|:443... failed: Connection refused.
Resolving corballis.co.uk (corballis.co.uk)... 83.86.93.178
Connecting to corballis.co.uk (corballis.co.uk)|83.86.93.178|:443... failed: Connection refused.

I’m using Nginx and that seems to be okay

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events { worker_connections 768; # multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on; # ssl_client_certificate /etc/nginx/ssl/cloudflare.crt; ssl_verify_client on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # gzip_types text/html text/plain text/css image/*;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
# configuration file /etc/nginx/modules-enabled/50-mod-http-auth-pam.conf:
load_module modules/ngx_http_auth_pam_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-dav-ext.conf:
load_module modules/ngx_http_dav_ext_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-echo.conf:
load_module modules/ngx_http_echo_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-geoip.conf:
load_module modules/ngx_http_geoip_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-image-filter.conf:
load_module modules/ngx_http_image_filter_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-subs-filter.conf:
load_module modules/ngx_http_subs_filter_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-upstream-fair.conf:
load_module modules/ngx_http_upstream_fair_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-http-xslt-filter.conf:
load_module modules/ngx_http_xslt_filter_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-mail.conf:
load_module modules/ngx_mail_module.so;
# configuration file /etc/nginx/modules-enabled/50-mod-stream.conf:
load_module modules/ngx_stream_module.so;
# configuration file /etc/nginx/mime.types:
types { text/html html htm shtml; text/css css; text/xml xml; image/gif gif; image/jpeg jpeg jpg; application/javascript js; application/atom+xml atom; application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg svgz;
image/webp webp;
application/font-woff woff;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
# configuration file /etc/nginx/sites-enabled/corballis.co.uk:
server { listen 80; listen 443 ssl;
# listen [::]:80;
# listen [::]:443 ssl;
server_name corballis.co.uk
root /var/www/
location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_pass
}
location ~ /.well-known { allow all;
}
client_max_body_size 50m;
}
# configuration file /etc/nginx/sites-enabled/sarahcorballis.com:
server { listen 80; listen 443 ssl;
# listen [::]:80;
# listen [::]:443 ssl;
server_name sarahcorballis.com
root /var/www/
index index.html;
try_files $uri $uri/ /index.html;
location ~ /.well-known { allow all;
}
client_max_body_size 50m;
}

I think my firewall rules are okay but here’s UFW status:

Status: active

To Action From
-- ------ ----
22/tcp ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
Nginx Full ALLOW Anywhere
5900:5910/tcp ALLOW Anywhere
631/tcp ALLOW Anywhere
9191/tcp ALLOW Anywhere
3306 ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
5900:5910/tcp (v6) ALLOW Anywhere (v6)
631/tcp (v6) ALLOW Anywhere (v6)
9191/tcp (v6) ALLOW Anywhere (v6)
3306 (v6) ALLOW Anywhere (v6) 

And just to be sure, here’s the output of iptables-save:

# Generated by iptables-save v1.6.0 on Mon Jan 4 22:55:28 2021
*nat
:PREROUTING ACCEPT [111326:20063761]
:INPUT ACCEPT [12845:2431611]
:OUTPUT ACCEPT [14360:1277629]
:POSTROUTING ACCEPT [14360:1277629]
-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8000
COMMIT
# Completed on Mon Jan 4 22:55:28 2021
# Generated by iptables-save v1.6.0 on Mon Jan 4 22:55:28 2021
*filter
:INPUT DROP [98:15256]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:ufw-after-forward - [0:0]
:ufw-after-input - [0:0]
:ufw-after-logging-forward - [0:0]
:ufw-after-logging-input - [0:0]
:ufw-after-logging-output - [0:0]
:ufw-after-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-before-input - [0:0]
:ufw-before-logging-forward - [0:0]
:ufw-before-logging-input - [0:0]
:ufw-before-logging-output - [0:0]
:ufw-before-output - [0:0]
:ufw-logging-allow - [0:0]
:ufw-logging-deny - [0:0]
:ufw-not-local - [0:0]
:ufw-reject-forward - [0:0]
:ufw-reject-input - [0:0]
:ufw-reject-output - [0:0]
:ufw-skip-to-policy-forward - [0:0]
:ufw-skip-to-policy-input - [0:0]
:ufw-skip-to-policy-output - [0:0]
:ufw-track-forward - [0:0]
:ufw-track-input - [0:0]
:ufw-track-output - [0:0]
:ufw-user-forward - [0:0]
:ufw-user-input - [0:0]
:ufw-user-limit - [0:0]
:ufw-user-limit-accept - [0:0]
:ufw-user-logging-forward - [0:0]
:ufw-user-logging-input - [0:0]
:ufw-user-logging-output - [0:0]
:ufw-user-output - [0:0]
-A INPUT -j ufw-before-logging-input
-A INPUT -j ufw-before-input
-A INPUT -j ufw-after-input
-A INPUT -j ufw-after-logging-input
-A INPUT -j ufw-reject-input
-A INPUT -j ufw-track-input
-A FORWARD -j ufw-before-logging-forward
-A FORWARD -j ufw-before-forward
-A FORWARD -j ufw-after-forward
-A FORWARD -j ufw-after-logging-forward
-A FORWARD -j ufw-reject-forward
-A FORWARD -j ufw-track-forward
-A OUTPUT -j ufw-before-logging-output
-A OUTPUT -j ufw-before-output
-A OUTPUT -j ufw-after-output
-A OUTPUT -j ufw-after-logging-output
-A OUTPUT -j ufw-reject-output
-A OUTPUT -j ufw-track-output
-A ufw-after-input -p udp -m udp --dport 137 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 138 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp -m tcp --dport 139 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp -m tcp --dport 445 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 67 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 68 -j ufw-skip-to-policy-input
-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
-A ufw-after-logging-forward -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-after-logging-input -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 4 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A ufw-before-forward -j ufw-user-forward
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP
-A ufw-before-input -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 4 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A ufw-before-input -p udp -m udp --sport 67 --dport 68 -j ACCEPT
-A ufw-before-input -j ufw-not-local
-A ufw-before-input -d 224.0.0.251/32 -p udp -m udp --dport 5353 -j ACCEPT
-A ufw-before-input -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j ACCEPT
-A ufw-before-input -j ufw-user-input
-A ufw-before-output -o lo -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -j ufw-user-output
-A ufw-logging-allow -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW ALLOW] "
-A ufw-logging-deny -m conntrack --ctstate INVALID -m limit --limit 3/min --limit-burst 10 -j RETURN
-A ufw-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP
-A ufw-skip-to-policy-forward -j DROP
-A ufw-skip-to-policy-input -j DROP
-A ufw-skip-to-policy-output -j ACCEPT
-A ufw-track-output -p tcp -m conntrack --ctstate NEW -j ACCEPT
-A ufw-track-output -p udp -m conntrack --ctstate NEW -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 22 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 443 -j ACCEPT
-A ufw-user-input -p tcp -m multiport --dports 80,443 -m comment --comment "\'dapp_Nginx%20Full\'" -j ACCEPT
-A ufw-user-input -p tcp -m multiport --dports 5900:5910 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 631 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 9191 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 3306 -j ACCEPT
-A ufw-user-input -p udp -m udp --dport 3306 -j ACCEPT
-A ufw-user-limit -m limit --limit 3/min -j LOG --log-prefix "[UFW LIMIT BLOCK] "
-A ufw-user-limit -j REJECT --reject-with icmp-port-unreachable
-A ufw-user-limit-accept -j ACCEPT
COMMIT
# Completed on Mon Jan 4 22:55:28 2021

Finally, to be sure there's something listening in the correct ports, I ran lsof -l :80 and :443, which give:

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 8578 www-data 6u IPv4 327276 0t0 TCP *:http (LISTEN)
nginx 8580 www-data 6u IPv4 327276 0t0 TCP *:http (LISTEN)
nginx 8582 www-data 6u IPv4 327276 0t0 TCP *:http (LISTEN)
nginx 8583 www-data 6u IPv4 327276 0t0 TCP *:http (LISTEN)
nginx 18370 root 6u IPv4 327276 0t0 TCP *:http (LISTEN)

and (443):

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 8578 www-data 8u IPv4 327278 0t0 TCP *:https (LISTEN)
nginx 8580 www-data 8u IPv4 327278 0t0 TCP *:https (LISTEN)
nginx 8582 www-data 8u IPv4 327278 0t0 TCP *:https (LISTEN)
nginx 8583 www-data 8u IPv4 327278 0t0 TCP *:https (LISTEN)
nginx 18370 root 8u IPv4 327278 0t0 TCP *:https (LISTEN)

I have tried to run Certbot to set up new Let’s Encrypt certificates but that fails, as I would expect, because it can’t get to the challenge directory via port 80 due to the redirect but for some reason (no doubt incompetence on my part) I’m completely unable to sort this mess out.

Any thoughts would be most gratefully received.

7

1 Answer

You need to whitelist the Let’s Ecrypt acme-challenge request.

While Let’s Ecrypt is cool — because it is free — Certbot won’t work if it can’t get the acme-challenge request fulfilled.

I had a similar issue with an Ubuntu 16.04 server that I manage. I had setup Let’s Encrypt in the past and it worked well, but at some point the Let’s Encrypt decided to change the way that they confirm host identity to use an acme-challenge request.

The problem is they provide utterly no guidance — aka: useless help — in how to get around the Catch-22 of having an active firewall that might block/reject those requests. And the solution is so head-shakingly easy it’s stunning they don’t provide it as a matter of course.

You need to add the request for /.well-known/acme-challenge to the input chain on your firewall. In my case — where I am using IPTables directly — I had to change my input chain from this:

-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 80,443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -d 224.0.0.251/32 -p udp -m udp --dport 5353 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -p ah -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited

To this:

-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 80,443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -d 224.0.0.251/32 -p udp -m udp --dport 5353 -j ACCEPT
-A INPUT -m string --string "GET /.well-known/acme-challenge" --algo kmp -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -p ah -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited

Note the addition of this acme-challenge specific rule:

-A INPUT -m string --string "GET /.well-known/acme-challenge" --algo kmp -j ACCEPT

That is the magic that will allow the Certbot triggered process to be able to retrieve the acme-challenge request. The rule is fairly simple between the INPUT and ACCEPT action:

  • -m string --string "GET /.well-known/acme-challenge": Tells the firewall to detect GET requests for the acme-challenge.
  • --algo kmp: Uses the kmp (aka: Knuth-Pratt-Morris) algorithm for string detection.

In your case I would adjust your ufw-user-input in the saved format it stores it in within /lib/ufw/user.rules (I believe) so the ufw-user-input chain looks like this:

-A ufw-user-input -p tcp -m tcp --dport 22 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 443 -j ACCEPT
-A ufw-user-input -p tcp -m multiport --dports 80,443 -m comment --comment "\'dapp_Nginx%20Full\'" -j ACCEPT
-A ufw-user-input -p tcp -m multiport --dports 5900:5910 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 631 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 9191 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 3306 -j ACCEPT
-A ufw-user-input -p udp -m udp --dport 3306 -j ACCEPT
-A ufw-user-input -m string --string "GET /.well-known/acme-challenge" --algo kmp -j ACCEPT
-A ufw-user-limit -m limit --limit 3/min -j LOG --log-prefix "[UFW LIMIT BLOCK] "
-A ufw-user-limit -j REJECT --reject-with icmp-port-unreachable
-A ufw-user-limit-accept -j ACCEPT

I don’t have enough comfort or knowledge to know how to handle this from the command line of Ubuntu 18.04 using ufw but if someone out there can convert that line into a valid ufw command that would place it in the ufw-user-input chain, please feel free to share that in the comments.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like