A lot of web applications require being called over https
, which is a good thing. It's possible to configure this requirement at the web- or proxy server level, where nginx
or apache
will just redirect every request on http
to https
. Some applications additionally detect if the URL they've been called with contains the http
or the https
scheme and issue their own redirect response (usually 301
or 302
) to https
. This card is for the later kind.
The Problem
When you want to test your application directly on the VM it's running and usually it's the proxy server or webserver that does handles SSL, the port where the application is running is often times only responding to http
requests without SSL. However the application will still redirect to https
URLs which might not work for testing directly on the VM.
$ curl -v http://localhost:12345
* Trying 127.0.0.1:12345...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 12345 (#0)
> GET / HTTP/1.1
> Host: localhost:12345
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Date: Wed, 26 Apr 2023 06:38:09 GMT
< Server: Apache
< Location: https://localhost:12345/
< Content-Length: 0
< Status: 301 Moved Permanently
< Connection: close
< Content-Type: text/html
<
* Closing connection 0
$ curl -v https://localhost:12345
* Trying 127.0.0.1:12345...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 12345 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* error:1408F10B:SSL routines:ssl3_get_record:wrong version number
* Closing connection 0
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
We've manually followed the 301
redirect here and ended up expecting https
traffic on a port that only responds with unencrypted http
traffic, hence the not so obvious error message.
The Solution
Most applications respect the "X-Forwarded-Proto: https"
header that most reverse proxies set when handling SSL on their end and forwarding requests to the application. This is how the proxy server tells the application which schema the client used when calling the URL in the first place.
$ curl -IH "X-Forwarded-Proto: https" http://localhost:12345
HTTP/1.1 200 OK
#[…] rest of the regular http response truncated