Nginx
Nginx 在 docker 中找不到 ssl_certificate,即使它在那裡
我在 AWS EB 上執行 multidocker。設置如下所示:
Dockerrun.aws.json
(xxx 作為域的佔位符。該應用程序不安全){ "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; } }
解釋:
密鑰文件需要由
certbot
容器創建。為此,挑戰被放置在cert-challenge
體積中並由nginx-cert-proxy
容器暴露。這行得通。不起作用的是將證書應用於
nginx-proxy
容器。它失敗並出現以下錯誤: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)
現在簡單的解釋是有一些拼寫錯誤,或者 nginx 由於來自 certbot 的符號連結而搞砸了。
但我已將 bash 更改
nginx.conf
為預設值,在容器內啟動 bash,然後 ls 顯示: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
所以文件存在。關於符號連結,它絕對不是連結,而是一個實際的文件。修改後的 certbot 映像允許添加複制命令,因為入口點是
bash
.我完全迷路了。為什麼nginx無法讀取文件?
原來這是一個時間問題。
當所有容器同時啟動時,不會在 nginx 查找之前生成證書。當我手動進入容器進行檢查時,它們已同時生成並且可以正常工作。所以這是一個添加一個問題
until [ -f $cert ]; do sleep 1; done
在 nginx 執行命令之前。
我沒有考慮這一點,因為我忘記了每次執行設置時都會刪除證書。
我對此進行測試的方式是通過 EB CLI 的部署命令。這每次都會創建一個新版本的應用程序,導致儲存被刷新。