Docker-letsencrypt-nginx-proxy-companion: Non-HTTP support

Created on 7 Apr 2020  路  6Comments  路  Source: nginx-proxy/docker-letsencrypt-nginx-proxy-companion

I have a service which doesn't expose an HTTP interface. Rather, it uses a VOIP protocol over TLS.

Up until now, I've run a separate service which _does_ expose HTTP, so I've been able to "share" certificates between the two.

I'm now looking to move off my web service, and I'd like to know if there was a way I could trigger LetsEncrypt and Nginx to set up the necessary plumbing in order to answer ACME challenges, while _not requiring_ the container to expose an HTTP interface.

More info needed

Most helpful comment

@buchdag, I believe your first example is what I was after. I wanted to be able to generate a certificate for a domain name, even if that domain name (VIRTUAL_HOST and LETSENCRYPT_HOST) didn't expose an HTTP interface.

I assumed that nginx-proxy would require a container to EXPOSE some port in order to trigger the Letsencrypt cert generation, but after thinking about it and reviewing the code and experimenting, I was wrong. I was able to generate a cert for a test container that exposes no ports:

version: 3
services:
  cert_test:
    image: busybox
    environment:
      VIRTUAL_HOST: cert_test.mydomain.com
      LETSENCRYPT_HOST: cert_test.mydomain.com
      LETSENCRYPT_TEST: 'true'
    command: [
      'sleep', '600'
    ]

I can then:

  1. Verify the certificate had been created, and
  2. Realize that an nginx reverse proxy config may be auto-created (in order to support ACME negotiation), but that I can actually use this certificate however I wish:
$ curl -vskL https://cert_test.mydomain.com > /dev/null 
...
*  subject: CN=cert_test.mydomain.com
*  start date: Jul 14 16:04:37 2020 GMT
*  expire date: Oct 12 16:04:37 2020 GMT
*  issuer: CN=Fake LE Intermediate X1
> GET / HTTP/2
> Host: cert_test.mydomain.com
> user-agent: curl/7.68.0
> accept: */*
> 
< HTTP/2 502 
< server: nginx/1.17.6
< date: Tue, 14 Jul 2020 17:13:02 GMT
< content-type: text/html
< content-length: 157
< strict-transport-security: max-age=31536000
< 
...

I should have just tested this to begin with, rather than making a post about it. Sorry for the noise.

All 6 comments

I believe this is (and should be) answered by Letsencrypt documentation:
https://letsencrypt.org/docs/challenge-types/
There are some other ways documented there to prove you own the domain name, without using HTTP, but since this project is about supporting an nginx proxy for HTTP, I think you are asking in the wrong place?

@KetchupBomb do you mean not requiring the proxyed container to expose an HTTP interface or not exposing an HTTP interface at all period ?

@buchdag, I believe your first example is what I was after. I wanted to be able to generate a certificate for a domain name, even if that domain name (VIRTUAL_HOST and LETSENCRYPT_HOST) didn't expose an HTTP interface.

I assumed that nginx-proxy would require a container to EXPOSE some port in order to trigger the Letsencrypt cert generation, but after thinking about it and reviewing the code and experimenting, I was wrong. I was able to generate a cert for a test container that exposes no ports:

version: 3
services:
  cert_test:
    image: busybox
    environment:
      VIRTUAL_HOST: cert_test.mydomain.com
      LETSENCRYPT_HOST: cert_test.mydomain.com
      LETSENCRYPT_TEST: 'true'
    command: [
      'sleep', '600'
    ]

I can then:

  1. Verify the certificate had been created, and
  2. Realize that an nginx reverse proxy config may be auto-created (in order to support ACME negotiation), but that I can actually use this certificate however I wish:
$ curl -vskL https://cert_test.mydomain.com > /dev/null 
...
*  subject: CN=cert_test.mydomain.com
*  start date: Jul 14 16:04:37 2020 GMT
*  expire date: Oct 12 16:04:37 2020 GMT
*  issuer: CN=Fake LE Intermediate X1
> GET / HTTP/2
> Host: cert_test.mydomain.com
> user-agent: curl/7.68.0
> accept: */*
> 
< HTTP/2 502 
< server: nginx/1.17.6
< date: Tue, 14 Jul 2020 17:13:02 GMT
< content-type: text/html
< content-length: 157
< strict-transport-security: max-age=31536000
< 
...

I should have just tested this to begin with, rather than making a post about it. Sorry for the noise.

@KetchupBomb you don't need to (and shouldn't) use a dummy container to generate certificates that aren't tied to an actual proxied service, this is what the standalone certificate feature is meant for.

@buchdag, I _do_ use the certificate for the container, but over a "raw" TCP connection, secured by TLS with the server -- not HTTP.

But my example shows that even if you didn't have that raw TCP connection, you could still get a cert for other purposes.

I have a lot of setups similar to yours and I strongly recommend against generating certificates for those non HTTP containers using VIRTUAL_HOST / LETSENCRYPT_HOST env var on them. You really should be using the standalone certificate feature instead to avoid running into issues (among them the race condition I just described here).

Was this page helpful?
0 / 5 - 0 ratings