Fun with HTTPS/H2 Part 1

Spooling out a new HTTPS/HTTP2 app with tools like nginx and Let’s Encrypt is pretty easy these days. Converting current HTTP apps to HTTPS is where all the fun happens. And by fun I mean swearing.

There are all kinds of good reasons to move to HTTPS, even if there’s not a single thing on your site you wouldn’t Tweet in all caps from the mountain top. Public Wifi hotspots or even your own router can modify your HTTP content before it gets to the user. And that’s just mundane quasi-legal stuff. It isn’t just about keeping content away from prying eyes, it’s about keeping your content intact.

HTTP2 also has a lot of good things to say for itself, but you could sum it up with faster. Although there’s nothing in the HTTP2 spec saying it requires a secure connection, all the browsers require it, so you’re not getting HTTP2 without HTTPS.

I’m moving one of our servers to HTTPS/HTTP2, and…wrinkles abound. I’m starting small with our tile server, which sits by itself on tiles.mcmap.org. How hard could that be?

First thing I did was go to certbot and get some instructions on aquiring a certificate for Nginx and Ubuntu (it’s hosted on a Digital Ocean droplet). And face planted.

1
Invalid response from http://tiles.mcmap.org/.well-known/acme-challenge/xd7VVkpRwg6587WsOp1MOAn6CDCvRFst_SzkTqbGo9s

The hell? Acme? Isn’t that the thing that gets the coyote killed every time?

I was getting this because tiles.mcmap.org is a Nginx proxy to a Node Express server. Rather than sully my beautiful Node app to handle this, I had Nginx send it someplace else.

1
2
3
location ~ /\.well-known/acme-challenge {
root /opt/apps/mcmap.org;
}

Ha! Tricked you sucker. Now I’ve got certs. I just need to redirect HTTP requests to HTTPS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 80;
server_name tiles.mcmap.org;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name tiles.mcmap.org;

# SSL stuff
ssl_certificate /etc/letsencrypt/live/tiles.mcmap.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tiles.mcmap.org/privkey.pem;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";

location / {
proxy_pass http://localhost:3000;
}

location ~ /\.well-known/acme-challenge {
root /opt/apps/mcmap.org;
}
}

Guess what didn’t work. That! That didn’t work. Although the Node app is setting the proper CORS response, and the server is sending you there, apparently the server sending you to the server needs its own CORS repsonse. So…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
listen 80;
server_name tiles.mcmap.org;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name tiles.mcmap.org;

# SSL stuff
ssl_certificate /etc/letsencrypt/live/tiles.mcmap.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tiles.mcmap.org/privkey.pem;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";

location / {
proxy_pass http://localhost:3000;
}

location ~ /\.well-known/acme-challenge {
root /opt/apps/mcmap.org;
}
}

Ye olde tile server is now rocking HTTPS/HTTP2, and current HTTP connections are being seamlessly redirected. A little trickier than I anticipated but not too bad. Next up is the real fun stuff - the actual apps.