Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Lets Encrypt SSL #26

Closed
Netherdrake opened this issue Nov 28, 2016 · 17 comments
Closed

[Feature Request] Lets Encrypt SSL #26

Netherdrake opened this issue Nov 28, 2016 · 17 comments

Comments

@Netherdrake
Copy link

Are there any plans to add Lets Encrypt SSL support as an option to deployment.

I think this would be a killer feature.

If not, do you happen to know any good ways to setup nginx or other reverse proxy in combination with meteor-launchpad?

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

I use Let's Encrypt for just about everything these days. I don't think you want that in your app container though. You want that at the proxy or load balancer level. My favorite these days is this one...

https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion

(which works with jwilder/nginx-proxy)
https://github.com/jwilder/nginx-proxy

@jshimko jshimko closed this as completed Nov 28, 2016
@Netherdrake
Copy link
Author

Netherdrake commented Nov 28, 2016

Do you happen to run it with docker-compose, with automatic certificate generation?

Edit: I found one in examples:
https://github.com/fatk/docker-letsencrypt-nginx-proxy-companion-examples/blob/master/docker-compose/v2/simple-site/docker-compose.yml

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

I don't usually use docker-compose for that because the Let's Encrypt container requires a somewhat longer than normal startup time and the app container would start before the LE container is ready.

So...

# start Nginx proxy
docker run -d -p 80:80 -p 443:443 \
  --name nginx-proxy \
  --restart always \
  -v /opt/certs:/etc/nginx/certs:ro \
  -v /etc/nginx/vhost.d \
  -v /usr/share/nginx/html \
  -v /var/run/docker.sock:/tmp/docker.sock:ro \
  jwilder/nginx-proxy:latest

# start Let's Encrypt helper
docker run -d \
  --restart always \
  -v /opt/certs:/etc/nginx/certs:rw \
  --volumes-from nginx-proxy \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  jrcs/letsencrypt-nginx-proxy-companion:latest

Then make sure to hop into the logs for the LE container and watch for it to be done setting up. Once it's ready, you can start your app container with the two required env vars.

docker run -d \
  -e VIRTUAL_HOST="example.com" \
  -e VIRTUAL_PORT="3000" \ # default port for meteor-launchpad
  -e LETSENCRYPT_EMAIL="me@example.com" \
  -e LETSENCRYPT_HOST="example.com" \
  -e ROOT_URL="https://example.com" \
  -e MONGO_URL="mongodb://..." \
  me/myapp:latest

You can then hop back into the logs for the LE container and you should see it generate the certs. Assuming your domain name is already pointed at your server, it should work within a few seconds. Renewals will then happen automatically.

You could obviously put all of that into a docker-compose.yml file, but you'd have to make sure that things come up in the right order and that the app container doesn't start before the LE container is ready.

Note that in my example above, your certs will be persisted to /opt/certs on your host, so you can update the containers and the certs will still be there when the containers come back up.

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

But if you really wanted to use docker-compose...

nginx-proxy:
  image: jwilder/nginx-proxy:latest
  ports:
    - 80:80
    - 443:443
  restart: always
  volumes:
    - /opt/certs:/etc/nginx/certs:ro
    - /etc/nginx/vhost.d
    - /var/run/docker.sock:/tmp/docker.sock:ro
    - /usr/share/nginx/html

lets-encrypt:
  image: jrcs/letsencrypt-nginx-proxy-companion:latest
  restart: always
  volumes:
    - /opt/certs:/etc/nginx/certs
    - /var/run/docker.sock:/var/run/docker.sock:ro
  volumes_from:
    - nginx-proxy

app:
  image: me/myapp:latest
  restart: always
  environment:
    - VIRTUAL_HOST=example.com
    - VIRTUAL_PORT=3000
    - LETSENCRYPT_EMAIL=me@example.com
    - LETSENCRYPT_HOST=example.com
    - ROOT_URL=https://example.com
    - MONGO_URL=mongodb://...

Then just start them one at a time.

# start nginx
docker-compose up -d nginx-proxy

# start LE helper
docker-compose up -d lets-encrypt

# watch logs and wait to be ready...
docker-compose logs -f lets-encrypt

# start app
docker-compose up -d app

@Netherdrake
Copy link
Author

Is there a way to make meteor-launchpad host on port 80 rather than 3000?

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

docker run -p 80:3000 ...

But if you're running nginx proxy in front of it, that's irrelevant anyway. You run nginx on 80 and set the backend port that nginx should talk to with VIRTUAL_PORT as I did above.

@Netherdrake
Copy link
Author

I am trying to make it work with haproxy rather than nginx, and if I expose the port with 80:3000 it doesn't work for some reason.

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

You can't have two containers exposing the same port on the same server.

@Netherdrake
Copy link
Author

Netherdrake commented Nov 28, 2016

I know, thats not the problem.

If I try sample app (https://github.com/docker/dockercloud-hello-world) it works fine.

If I try my meteor web app, and expose 80:3000, haproxy simply returns 503, no servers available.

I'd like to use letsencrypt-nginx-proxy-companion:latest, however Im deploying on dockercloud, and it doesn't work there. So Im trying to get this to work instead.

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

I don't know. Sounds like a config issue or your app possibly isn't responding to requests. It's not anything to do with this image though. I and many others use it every day to do the same exact thing you're trying to do.

Either way, you shouldn't need to expose port 80 on the app container to make haproxy work. Just point haproxy at 3000.

Or use any of the stuff I wrote out above. It works as-is. You can literally copy/paste it and add your own app container details.

@Netherdrake
Copy link
Author

Im sure it is not meteor-launchpad issue.

So far, it looks like haproxy won't listen on public 80 port, so I'd perhaps need to do something like:

expose:
 - '80'

Which is why I asked if meteor-launchpad can make meteor run on port 80.

I tried setting haproxy TCP_PORTS to 3000, and MODE to http, but that doesn't seem to work either.

I have literally no clue of what I'm doing, sorry if Im bugging you with questions much.

@Netherdrake
Copy link
Author

Netherdrake commented Nov 28, 2016

Ok, I've given up on haproxy, and decided to try nginx-proxy, however I'm running into the same error:

503 Service Temporarily Unavailable
nginx/1.11.3

My docker config:

lets-encrypt:
  image: 'jrcs/letsencrypt-nginx-proxy-companion:latest'
  restart: always
  tags:
    - steemsports
  volumes:
    - '/opt/certs:/etc/nginx/certs'
    - '/var/run/docker.sock:/var/run/docker.sock:ro'
  volumes_from:
    - nginx-proxy
nginx-proxy:
  image: 'jwilder/nginx-proxy:latest'
  ports:
    - '80:80'
    - '443:443'
  restart: always
  tags:
    - steemsports
  volumes:
    - '/opt/certs:/etc/nginx/certs:ro'
    - /etc/nginx/vhost.d
    - '/var/run/docker.sock:/tmp/docker.sock:ro'
    - /usr/share/nginx/html
web:
  autoredeploy: true
  environment:
    - LETSENCRYPT_EMAIL=hidden
    - LETSENCRYPT_HOST=preview.steemsports.com
    - 'MONGO_URL=hidden'
    - 'ROOT_URL=https://preview.steemsports.com/'
    - VIRTUAL_HOST=preview.steemsports.com
    - VIRTUAL_PORT=3000
  image: 'furion/steemsports-web:latest'
  restart: always
  tags:
    - steemsports

I've started nginx-proxy first, then LE, then web app.

LE output:

[lets-encrypt-1]2016-11-28T20:03:00.242650199Z parse error: Invalid numeric literal at line 1, column 3
[lets-encrypt-1]2016-11-28T20:03:00.243910702Z Warning: '/etc/nginx/certs' does not appear to be a mounted volume.
[lets-encrypt-1]2016-11-28T20:03:00.253161011Z parse error: Invalid numeric literal at line 1, column 3
[lets-encrypt-1]2016-11-28T20:03:00.254331448Z Warning: '/etc/nginx/vhost.d' does not appear to be a mounted volume.
[lets-encrypt-1]2016-11-28T20:03:00.267364301Z parse error: Invalid numeric literal at line 1, column 3
[lets-encrypt-1]2016-11-28T20:03:00.267775667Z Warning: '/usr/share/nginx/html' does not appear to be a mounted volume.
[lets-encrypt-1]2016-11-28T20:03:00.284010902Z Sleep for 3600s
[lets-encrypt-1]2016-11-28T20:03:00.347398574Z 2016/11/28 20:03:00 Generated '/app/letsencrypt_service_data' from 2 containers
[lets-encrypt-1]2016-11-28T20:03:00.347445391Z 2016/11/28 20:03:00 Running '/app/update_certs'
[lets-encrypt-1]2016-11-28T20:03:00.353107948Z 2016/11/28 20:03:00 Watching docker events
[lets-encrypt-1]2016-11-28T20:03:00.366586383Z Reloading nginx proxy...
[lets-encrypt-1]2016-11-28T20:03:00.421315594Z 2016/11/28 20:03:00 Contents of /app/letsencrypt_service_data did not change. Skipping notification '/app/update_certs'
[lets-encrypt-1]2016-11-28T20:03:00.575676108Z �Q2016/11/28 20:03:00 Generated '/etc/nginx/conf.d/default.conf' from 2 containers
[lets-encrypt-1]2016-11-28T20:03:00.590912288Z �;2016/11/28 20:03:00 [notice] 51#51: signal process started
[lets-encrypt-1]2016-11-28T20:03:00.592228552Z Creating/renewal preview.steemsports.com certificates... (preview.steemsports.com)
[lets-encrypt-1]2016-11-28T20:03:01.335406961Z 2016-11-28 20:03:01,332:INFO:simp_le:1383: Certificates already exist and renewal is not necessary, exiting with status code 1.
[lets-encrypt-1]2016-11-28T20:03:01.377512561Z Sleep for 3600s
[lets-encrypt-1]2016-11-28T20:07:28.048390032Z 2016/11/28 20:07:28 Received event die for container 9f275a0d0514
[lets-encrypt-1]2016-11-28T20:07:28.561427575Z 2016/11/28 20:07:28 Received event stop for container 9f275a0d0514
[lets-encrypt-1]2016-11-28T20:07:32.913395287Z 2016/11/28 20:07:32 Received event start for container 00c12b93e375
[lets-encrypt-1]2016-11-28T20:07:47.913567562Z 2016/11/28 20:07:47 Debounce minTimer fired
[lets-encrypt-1]2016-11-28T20:07:47.982855471Z 2016/11/28 20:07:47 Generated '/app/letsencrypt_service_data' from 2 containers
[lets-encrypt-1]2016-11-28T20:07:47.982903482Z 2016/11/28 20:07:47 Running '/app/update_certs'
[lets-encrypt-1]2016-11-28T20:07:47.998515899Z Creating/renewal preview.steemsports.com certificates... (preview.steemsports.com)
[lets-encrypt-1]2016-11-28T20:07:48.719681502Z 2016-11-28 20:07:48,717:INFO:simp_le:1383: Certificates already exist and renewal is not necessary, exiting with status code 1.
[lets-encrypt-1]2016-11-28T20:07:48.762292259Z Sleep for 3600s

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

Sounds like a problem with your app - which I don't have access to.

@Netherdrake
Copy link
Author

Netherdrake commented Nov 28, 2016

Ugh, I have spent a few hours chasing my tail - all for nothing. I assume there was nothing wrong with haproxy config either.

The issue was an incorrect Cloudflare setting. Changing SSL from Flexible to Full (strict) fixed the issue.

Everything 'just works' now.

@jshimko
Copy link
Owner

jshimko commented Nov 28, 2016

Isn't that always how it is? :)

Glad to hear it's working.

@Netherdrake
Copy link
Author

Just for kicks of it, I got it to work on haproxy as well (on port 3000). The trick is to set FORCE_SSL and VIRTUAL_HOST vars.

haproxy:
  image: 'interaction/haproxy:master'
  links:
    - letsencrypt
    - web
  ports:
    - '80:80'
    - '443:443'
  roles:
    - global
  tags:
    - steemsports-web
  volumes_from:
    - letsencrypt
letsencrypt:
  environment:
    - DOMAINS=preview2.steemsports.com
    - EMAIL=HIDDEN
  expose:
    - '80'
  image: 'interaction/letsencrypt:master'
  tags:
    - steemsports-web
web:
  autoredeploy: true
  environment:
    - FORCE_SSL=yes
    - 'VIRTUAL_HOST=https://*'
    - 'MONGO_URL=HIDDEN'
    - 'ROOT_URL=https://preview2.steemsports.com/'
  expose:
    - '3000'
  image: 'furion/steemsports-web:latest'
  restart: always
  tags:
    - steemsports-web

@joshontheweb
Copy link

I have run into this same issue. I'm curious why a misconfiguration in cloudflare would cause the container to not think the directories are mounted. I use cloudflare but only for dns. I don't route any ssl/traffic through them. I can log into the container and navigate to the directories that it says aren't mounted. Any insight on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants