I'm running multidocker on AWS EB. The setup looks like this:
Dockerrun.aws.json
(xxx as placeholder for the domain. The app is not secure)
{
"AWSEBDockerrunVersion": 2,
"volumes": [
{
"name": "nginx-conf",
"host": {
"sourcePath": "/var/app/current/nginx.conf"
}
},
{
"name": "nginx-cert-conf",
"host": {
"sourcePath": "/var/app/current/nginx.cert.conf"
}
},
{
"name": "cert-bot-lib",
"host": {
"sourcePath": "/var/app/current/django_project/certbot"
}
},
{
"name": "lets-encrypt",
"host": {
"sourcePath": "/var/app/current/django_project/certs"
}
},
{
"name": "cert-challenge",
"host": {
"sourcePath": "/var/app/current/django_project/cert_challenge"
}
}
],
"containerDefinitions": [{
"name": "web-app",
"image": "xxx",
"command": [
"…"
],
"essential": true,
"memory": 1000,
"mountPoints": [
…
]
},
{
"name": "channels-app",
"image": "xxx",
"command": [
"…"
],
"essential": true,
"memory": 1000,
"mountPoints": [
…
]
},
{
"name": "nginx-proxy",
"image": "nginx",
"essential": false,
"memory": 500,
"portMappings": [{
"hostPort": 443,
"containerPort": 443
}],
"links": ["web-app", "channels-app"],
"mountPoints": [{
"sourceVolume": "nginx-conf",
"containerPath": "/etc/nginx/conf.d/default.conf",
"readOnly": true
},
{
"sourceVolume": "lets-encrypt",
"containerPath": "/etc/ssl/certs",
"readOnly": true
}
]
},
{
"name": "nginx-cert-proxy",
"image": "nginx",
"essential": true,
"memory": 250,
"portMappings": [{
"hostPort": 80,
"containerPort": 80
}],
"mountPoints": [{
"sourceVolume": "nginx-cert-conf",
"containerPath": "/etc/nginx/conf.d/default.conf",
"readOnly": true
},
{
"sourceVolume": "cert-challenge",
"containerPath": "/cert_challenge",
"readOnly": true
}
]
},
{
"name": "certbot",
"image": "yspreen/certbot-bash",
"command": [
"-c",
"(([ -d /etc/letsencrypt/live ] && certbot renew --staging --webroot --register-unsafely-without-email --agree-tos --no-eff-email --webroot-path=/cert_challenge) || certbot certonly --staging --webroot --register-unsafely-without-email --agree-tos --no-eff-email --webroot-path=/cert_challenge -d xxx) && cp -Lr /etc/letsencrypt/live /etc/letsencrypt/live_cp"
],
"essential": false,
"memory": 250,
"mountPoints": [{
"sourceVolume": "lets-encrypt",
"containerPath": "/etc/letsencrypt",
"readOnly": false
},
{
"sourceVolume": "cert-challenge",
"containerPath": "/cert_challenge",
"readOnly": false
},
{
"sourceVolume": "cert-bot-lib",
"containerPath": "/var/lib/letsencrypt",
"readOnly": false
}
]
}
]
}
nginx.conf
upstream djangomain {
server web-app:8000;
}
upstream djangochannels {
server channels-app:8001;
}
server {
server_name xxx;
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_tokens off;
disable_symlinks off;
ssl on;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
## OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1;
ssl_certificate /etc/ssl/certs/live_cp/xxx/fullchain.pem;
ssl_certificate_key /etc/ssl/certs/live_cp/xxx/privkey.pem;
location /ws/ {
proxy_pass http://djangochannels/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
location /static/ {
alias /static_root/;
autoindex on;
}
location / {
proxy_pass http://djangomain/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
nginx.cert.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location ~ /.well-known/acme-challenge {
allow all;
root /cert_challenge;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
Explanation:
The keyfiles need to be created by the certbot
container. For this, the challenge is placed in the cert-challenge
volume and exposed by the nginx-cert-proxy
container. This works.
What doesn't work is applying the certs to the nginx-proxy
container. It's failing with the following error:
nginx: [warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/conf.d/default.conf:17
nginx: [emerg] BIO_new_file("/etc/ssl/certs/live_cp/xxx/fullchain.pem") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/ssl/certs/live_cp/xxx/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)
Now the easy explanation would be that there's some typo, or nginx is messing up because of the symlinks from certbot.
But I've changed the nginx.conf
to the default, started bash inside the container, and ls shows:
root@a58f8e87ca:/# ls /etc/ssl/certs/live_cp/xxx/fullchain.pem -lAh
-rw-r--r-- 1 root root 3.8K Oct 25 21:43 /etc/ssl/certs/live_cp/xxx/fullchain.pem
So the file exists. And regarding symlinks, it's definitely no link but an actual file. The modified certbot image allows to add a copy command, because the entry point is bash
.
I'm completely lost. Why is nginx unable to read the file?