HTTPS med Cloudflares Flexible SSL

Marcus Olsson,

Nyligen så bestämde jag mig för att börja använda mig av HTTPS här på marcusolsson.me och stötte på ett litet frågetecken som jag antar att fler än jag någon gång kommer behöva tänka på.

Jag valde att använda mig av Cloudflares "Flexible SSL", vilket innebär att trafiken mellan webbläsaren och cloudflares servrar är kypterad – Cloudflare sitter i sin tur emellan min server och besökaren (läs mitt tidigare inlägg om Cloudflare om du vill veta mer om tjänsten) – min server använder sig alltså inte av ett eget utfärdat SSL-cerifikat.

'Cloudflare Flexible SSL'

Man kan lätt tro att för att använda sig av deras Flexible SSL så gör en standardkonfiguering i nginx, precis som om man använde ett vanligt SSL-certifikat eller Cloudflares "Full SSL":

1server {
2 listen 80;
3 server_name marcusolsson.me;
4 return 301 https://marcusolsson.me$request_uri;
5}
6
7server {
8 listen 443 ssl;
9 server_name marcusolsson.me;
10 root /xxx/marcusolsson.me;
11 [...]
12}
1server {
2 listen 80;
3 server_name marcusolsson.me;
4 return 301 https://marcusolsson.me$request_uri;
5}
6
7server {
8 listen 443 ssl;
9 server_name marcusolsson.me;
10 root /xxx/marcusolsson.me;
11 [...]
12}

Men icke, detta kommer att resultera i en redirect-loop som webbläsaren till slut avbryter.

'Chrome redirect loop' En redirect-loop i Google Chrome

Men varför? Jo – Cloudflares Flexible SSL lägger sig alltså endast mellan besökaren och Cloudflares servrar – trafiken till slutdestination (alltså ens egna server) kommer fortfarande att ske via port 80, inte standardporten för HTTPS; 443. Cloudflare kommer i sin tur (om alternativet är valt vill säga) alltid att erbjuda webbläsaren att ansluta via både HTTP och HTTPS.

Men hur tvingar man en HTTPS-anslutning då? Den enklaste metoden jag kunde hitta var följande:

1server {
2 listen 80;
3 server_name marcusolsson.me;
4 root /xxx/marcusolsson.me;
5
6 if ($http_x_forwarded_proto = "http") {
7 return 301 https://$server_name$request_uri;
8 }
9
10 [...]
11}
1server {
2 listen 80;
3 server_name marcusolsson.me;
4 root /xxx/marcusolsson.me;
5
6 if ($http_x_forwarded_proto = "http") {
7 return 301 https://$server_name$request_uri;
8 }
9
10 [...]
11}

Notera att endast ett server-block används.

Här kollar vi alltså om protokollet är HTTP, och om så är fallet så kör vi en 301:a till motsvarande HTTPS-sida.

För Apache så skulle en liknande metod kunna se ut som följande:

1RewriteCond %{HTTP:CF-Visitor} !'"scheme":"http"'
2RewriteRule ^(.*)$ https://marcusolsson.me$1 [L]
1RewriteCond %{HTTP:CF-Visitor} !'"scheme":"http"'
2RewriteRule ^(.*)$ https://marcusolsson.me$1 [L]