【问题标题】:Adding SSL certs to NGINX docker container将 SSL 证书添加到 NGINX docker 容器
【发布时间】:2018-12-26 05:56:51
【问题描述】:

我正在尝试将 SSL 证书(使用 LetsEncrypt 生成)添加到我的 nginx。 nginx 是从一个 docker-compose 文件构建的,我在该文件中创建了一个从主机到容器的卷,以便容器可以访问证书和私钥。

volumes:
  - /etc/nginx/certs/:/etc/nginx/certs/

当 nginx 容器启动并失败并出现以下错误时

[emerg] 1#1: BIO_new_file("/etc/nginx/certs/fullchain.pem") failed 
(SSL: error:02001002:system library:fopen:No such file or 
directory:fopen('/etc/nginx/certs/fullchain.pem','r') 
error:2006D080:BIO routines:BIO_new_file:no such file)

我的 nginx 配置文件如下所示:

server {
    listen 80;
    server_name server_blah www.server_blah;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name server_blah;
    ssl_certificate      /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key  /etc/nginx/certs/privkey.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
}

我错过了什么/做错了什么?

【问题讨论】:

标签: docker ssl nginx docker-compose ssl-certificate


【解决方案1】:

我现在遇到了完全相同的问题。相同的错误代码。

我在 .pem 文件上尝试了不同的方法:

  • 将权限 (chmod) 更改为:
    • 777
    • 755
    • 600
  • 将所有者 (chown) 更改为:
    • nginx(用户在 nginx.conf 中定义)
  • 将位置更改为:
    • /etc/ssl/certs
    • /etc/nginx/ssl
    • /etc/letsencrypt/live
  • 将 docker 安装更改为:
    • ro(只读)
    • rw(读写)

遗憾的是,这些解决方案都不适合我。

当我连接到容器终端时,即使我能够列出 (ls) 文件,nginx 似乎也无法找到这些文件。

为了提供更多详细信息,我在 Synology DS918+ NAS 上运行 Docker。

我希望这将有助于找到解决方案! 我会尝试各种事情,如果我能成功,我会回来的!

【讨论】:

  • 我解决了它,终于让它工作了。在下面写了一个冗长的答案。希望对你有帮助。
【解决方案2】:

终于破解了这个问题,并且能够在我的开发和生产站点上成功地重复该过程以使 SSL 证书正常工作!

抱歉帖子太长了!

在我的设置中,我在 ubuntu 16 机器上安装了 docker docker-compose。

任何遇到此问题的人都会详细说明我所做的步骤。

  1. 转到您的代码所在的目录

    cd /opt/example_dir/

  2. 为letsencrypt和它的站点创建一个目录。

    sudo mkdir -p /opt/example_dir/letsencrypt/letsencrypt-site

  3. 从letsencrypt目录创建准系统docker-compose.yml文件。

    sudo nano /opt/example_dir/letsencrypt/docker-compose.yml

添加以下内容:

    version: '2'

        services:
            image: nginx:latest
            ports:
              - "80:80"
            volumes:
              - ./nginx.conf:/etc/nginx/conf.d/default.conf
              - ./letsencrypt-site:/usr/share/nginx/html
            networks:
              - docker-network

        networks:
          docker-network:
            driver: bridge

* This will pull down the latest nginx version
* Expose port 80 
* Mount a config file (that i'll create later) 
* Maps the site directory so that we can have a simple test index.html for when 

我们启动简单的 nginx 容器。

  1. /opt/example_dir/letsencrypt中创建一个nginx.conf文件

    sudo nano /opt/example_dir/letsencrypt/nginx.conf

将以下内容放入其中

    server {
      listen 80;
      listen [::]:80;
      server_name example_server.com;

      location ~ /.well-known/acme-challenge {
          allow all;
          root /usr/share/nginx/html;
      }

      root /usr/share/nginx/html;
      index index.html;
    }

* This listens for requests on port 80 for the server with name example_server.com
* Gives the Certbot agent access to ./well-known/acme-challenge
* Sets the default root and file
  1. 接下来在/opt/example_dir/letsencrypt/letsencrypt-site中创建一个index.html文件

sudo nano /opt/example_dir/letsencrypt/letsencrypt-site/index.html

添加以下内容

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>LetsEncrypt Setup</title>
</head>
<body>

    <p>Test file for our http nginx server</p>
</body>
</html>

#### 基本 nginx 容器的所有部件就位!

  1. 现在我们启动 nginx 容器。

    cd /opt/example_dir/letsencrypt
    sudo docker-compose up -d
    

nginx 容器现已启动并运行,访问您定义的 url,您应该会返回测试 index.html 页面。此时我们已经准备好运行 certbot 命令来生成一些证书了

  1. 运行以下命令生成证书,将--email 替换为您的电子邮件

    sudo docker run -it --rm \
    -v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
    -v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
    -v /opt/example_dir/letsencrypt/letsencrypt-site:/data/letsencrypt \
    -v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
    certbot/certbot \
    certonly --webroot \
    --email youremail@domain.com --agree-tos --no-eff-email \
    --webroot-path=/data/letsencrypt \
    -d example.com
    
    • 以交互模式运行 docker,以便查看输出。
    • 完成生成证书后,它将自行删除。
    • 它将装载 4 个卷:
      1. 存储证书的letsencrypt文件夹/
      2. 一个 lib 文件夹
      3. 映射我们的站点文件夹
      4. 映射日志路径
    • 同意 ToS
    • 指定根网络路径
    • 指定要为其生成证书的服务器地址。

如果该命令运行正常,那么我们已经为该 Web 服务器生成了证书。我们现在可以在我们的生产站点中使用这些,并将 nginx 配置为使用 ssl 并使用这些证书!

  1. 关闭 nginx 容器

    cd /opt/example_dir/letsencrypt/
    sudo docker-compose down
    

设置生产 nginx 容器

目录结构现在应该是这样的。你有你的代码/网络应用项目,然后是我们上面创建的letsencrypt文件夹。

/opt/example_dir
             / -> project_folder
             / -> letsencrypt
  1. 创建文件夹调用 dh-param

    sudo mkdir -p /opt/example_dir/project_folder/dh-param
    
  2. 生成 dh 密钥

    sudo openssl dhparam -out /opt/example_dir/project_folder/dh-param/dhparam-2048.pem 2048
    
  3. 更新/opt/example_dir/project_folder内的docker-compose.yml和nginx.conf文件

project_folder 是我的源代码所在的位置,因此我在这里为 nginx 创建了一个生产配置文件,并更新 docker-compose.yml 以挂载我的 nginx 配置、dh-pharam 交换密钥以及我们之前创建的证书本身。

docker-compose 中的 nginx 服务

    nginx:
        image: nginx:1.11.3
        restart: always
        ports:
          - "80:80"
          - "443:443"
          - "8000:8000"
        volumes:
          - ./nginx.conf:/etc/nginx/conf.d/default.conf
          - ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem
          - /docker-volumes/etc/letsencrypt/live/exampleserver.com/fullchain.pem:/etc/letsencrypt/live/exampleserver.com/fullchain.pem
          - /docker-volumes/etc/letsencrypt/live/exampleserver.com/privkey.pem:/etc/letsencrypt/live/exampleserver.com/privkey.pem
        networks:
          - docker-network

        volumes_from:
          - flask
        depends_on:
          - flask
          - falcon
        links:
          - datastore

project_folder 中的 nginx.conf

error_log /var/log/nginx/error.log warn;

server {
    listen 80;
    listen [::]:80;

    server_name exampleserver.com

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }

    #for certbot challenges (renewal process)
    location ~ /.well-known/acme-challenge {
        allow all;
        root /data/letsencrypt;
    }
}

#https://exampleserver.com
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name exampleserver.com;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/exampleserver.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/exampleserver.com/privkey.pem;

    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 8.8.8.8;


    # Define the specified charset to the “Content-Type” response header field
    charset utf-8;
}

至此,一切就绪! (最后)

  1. 启动 docker 容器。

    cd /opt/example_dir/project_folder
    sudo docker-compose up -d
    
    # Check the docker log with:
    sudo docker logs -f -t  
    

我知道这需要很多步骤,但这就是我所做的,它对我有用,希望对其他人有所帮助。

【讨论】:

  • 在第 9 节之前一切正常,之后它会抛出一个错误:获取验证数据时出错
  • 如何更新证书?你自动化了吗?
  • @AntonyHatchkins 我使用 certbot 自动更新证书。您必须在 nginx 配置文件中添加一个部分。然后我设置了一个 cronjob 来触发证书更新检查。如果证书在到期后 30 天内得到更新
  • Afaik 默认情况下,crond 和 systemd 调度程序都不能在 docker 容器中工作。我遇到的大多数指南都通过 bash 中的 sleeping 自动更新。您是在主机上还是在容器中运行 cronjob?
  • @AntonyHatchkins 这已经很老了,所以我回顾了一下代码!原来我创建了一个名为 run_cron.py 的 python 脚本,它使用了 subprocess 模块和 call 方法。 call(["crond", "-f", "-L 15"])。我有一个用于所有服务的 docker-compose 文件。因此,对于每项服务,我都需要 cronjobs。我使用了command 选项。所以就像command: python3 /path/to/app/run_cron.py 回想起来,我记得在 crons 和 docker 容器中遇到了同样的问题,但是这个设置有效。可能有更好的方法,但它适合当时。
【解决方案3】:

我的解决方案:

我已通过以下方式将/etc/letsencrypt/live/mydomain.com/ 映射到/etc/nginx/certs/

volumes:
  - /etc/letsencrypt/live/mydomain.com/:/etc/nginx/certs/

在这种情况下,它已经映射了软符号链接。

lrwxrwxrwx 1 root root   38 Sep 15 00:21 chain.pem -> ../../archive/mydomain.com/chain1.pem
lrwxrwxrwx 1 root root   42 Sep 15 00:21 fullchain.pem -> ../../archive/mydomain.com/fullchain1.pem
lrwxrwxrwx 1 root root   40 Sep 15 00:21 privkey.pem -> ../../archive/mydomain.com/privkey1.pem

最后,我将volume 部分更改为:

volumes:
  - /etc/letsencrypt/archive/mydomain.com/:/etc/nginx/certs/

【讨论】:

    猜你喜欢
    • 2017-04-21
    • 2018-12-21
    • 1970-01-01
    • 2018-04-06
    • 2021-07-10
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2022-09-28
    相关资源
    最近更新 更多