I have a web app (Scala Play framework 2.5 based) that I would like to dockerize, but that insists on https and will redirect any http requests to https. I would like to use Caddy (also Dockerized) without changing the app (for now). Are there any documents or tutorials on how to achieve this? Most of what I have seen relies on the underlying app to receive http requests.
I have been reading the following link, which describe setting up https on a dev environment. Could they potentially be applicable for setting up https on the internal Docker network?
Please note. I don’t think the double https is necessary for the long run. I am just trying to get a workaround in place for now and over time we can phase out the unnecessary work the app is currently doing. On another project, I have a Scala Play framework 2.7 based web app working correctly with the following configs:
Hi @dnk8n, have you tried simply proxying to the app’s HTTPS endpoint?
If the HTTPS certificate provided by the app is not trusted, you can tell Caddy not to verify it using the insecure_skip_verify subdirective in your proxy. Note that this is, as mentioned, insecure - but not more so than using HTTP.
To be honest I am not sure about that, I am annoyingly abstracted away from how this app works. I am comfortable in Python, Scala not so much. I recently joined the team and their devs are not very good at getting back to me.
But one of their devs said that they could probably make a code change to disable auto https redirecting.
The behavior of the app is that if it senses an http request, it redirects to https. And for some reason in Play 2.5 this was done in code because there was not a simple config flag in 2.5 (play.filters.https.redirectEnabled = false works in Play 2.6+, see link)
That link should give a clearer idea of what is taking place.
I don’t know how to get an internal application to successfully respond to https on the internal Docker network.
If Caddy’s going straight to HTTPS, you shouldn’t need to worry about the redirect. You’ll need to sort out what the app needs to be able to talk over HTTPS.
What do you get when you run wget --server-response --spider ***-play-app:9000 from within the Caddy container? Should give us some insight into exactly what is going wrong.
I executed the command you gave me, and this is what I got @Whitestrake
Connecting to ***-play-app:9000 (172.18.0.3:9000)
HTTP/1.1 301 Moved Permanently
Location: https://***-play-app:9000/
Connecting to ***-play-app:9000 (172.18.0.3:9000)
ssl_client: ***-play-app: handshake failed: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
wget: error getting response: Connection reset by peer
Your app is redirecting HTTP visitors on port 9000… to HTTPS on port 9000.
Obviously the app can’t listen for HTTP and HTTPS on the same port. So when the client reconnects via HTTPS on port 9000, and gets a HTTP response, we see this issue.
Your app will need to be updated. It’s unworkable in its current state. It must either provide a real HTTPS listener, or it needs to accept HTTP, but right now it’s doing neither.
Now adding your original suggestion, it works slightly better. Although now I have to try understand why the application is redirecting to the main marketing page!
The only way I could work out how to get things working without resorting to self-signed certs for https and thereby being able to omit Caddy flag, insecure_skip_verify…
I only went through these extra steps going down the wrong rabbit hole… in the end it was simpler and more automated just to use insecure_skip_verify (because security at this layer is somewhat redundant, if I understand correctly))
First pass the app some extra ssl related flags it wanted:
So this meant I needed to create a wildcard cert on the host using certbot and mount the volume /etc/letsencrypt/live/***.co.za:/etc/letsencrypt/live/***.co.za into the play docker application. This way it can validate https requests. I also needed to port forward 9000 to the host (and create a security group rule for AWS so that only the instance itself can access port 9000).
The final caddy file looks like (any way to avoid this duplication btw? Are snippets the way?):
The DNS ‘A’ record of both demo..co.za and app..co.za point to the same host
this routes from host to forwarded (host ↔ caddy docker container) port 80 or 443 (the only ports open to the public)
this makes its way to dockerized caddy (see conf above)
Caddy proxies the request to https://demo.***.co.za:9000 (port 9000 only open to this instance, not the public)
Because of transparent directive, the application can derive demo or app from the host headers (which according to my understanding will remain the same no matter where caddy routes the request, is that right?)
Depending on app or demo, the corresponding web app is displayed
Note: I believe the reason I cannot route straight to the play app on the internal docker network is that I have no way of proving ownership of ‘***-play-app’. Therefore I have to go via external DNS and back to the instance through the domain name I have installed certs for.
Maybe there is a simpler way. But by the time I find out I won’t need it… because we will allow the app to receive http requests. Then the caddy conf would look more similar to the original one posted in this discussion.
Unless your threat model consists of malicious software inside your Docker networks, sniffing or impersonating traffic between Docker-run services, that somehow can’t access the TLS assets used inside your Docker containers, self-signed certificates are A-OK.
Yep - can’t do it without distributing your own CA, an arduous process at best, possible to automate but unwieldy.
Unfortunate this goes external, but at least it’s HTTPS secured if it does, haha.
Probably just as secure as unverified HTTPS when we’re talking about the inside of a controlled network. It’ll simplify things a lot.