首页 > 解决方案 > 如何在 Docker 容器中设置 SSL

问题描述

恢复

我有一Apache台服务器在生产中运行两个应用程序。我想实现在 Django 中制作的其他应用程序,由NginxDocker 容器提供服务。架构如下:

User request --> Apache --> Nginx inside Docker --> Gunicorn inside Docker --> Django app inside Docker

在此处输入图像描述

我想要的是

我想实现SSL certbot certificate,但我不知道应该如何使用 HTTPS 在主机(Apache)和容器(Nginx)之间建立通信。

  1. 我必须为 Apache 安装 Certbot 证书,而我可以为 Nginx 使用相同的证书吗?
  2. 主机中的 Apache 和容器中的 Nginx 之间的 HTTPS 重定向应该如何?.

我将这篇文章作为参考,其中实现了类似的架构,不同之处在于 Apache 安装在主机和 Docker 容器中,并且使用Certbot为两个服务器创建的相同证书,但我不知道相同的逻辑是否适用在 Apache 和 Nginx 等不同服务器之间。

我有的

Apache 主机服务器配置文件

<VirtualHost *:80>
        ServerName app.com.co
        ServerAdmin webmaster@app.com.co

        ErrorLog /var/log/app_com_co/error.log
        CustomLog /var/log/app_com_co/access.log combined

        ProxyPreserveHost On
        ProxyPass        "/" "http://127.0.0.1:1300/"
        ProxyPassReverse "/" "http://127.0.0.1:1300/"
</VirtualHost>
 
# Apache SSL Relate things in host

<VirtualHost *:443>
       ServerName app.com.co
       ServerAdmin webmaster@app.com.co

       ErrorLog /var/log/app_com_co/error.log
       CustomLog /var/log/app_com_co/access.log combined

       # Enable/Disable SSL for this virtual host.
       SSLEngine on

       # Activate SSL for proxy
       SSLProxyEngine On

       # Disable certificate verification in communication between host and container
       SSLProxyVerify none
       SSLProxyCheckPeerCN off
       SSLProxyCheckPeerName off
       SSLProxyCheckPeerExpire off

       # Defines that The host will pass the Host: line from the incoming request to
       # the container instead of the hostname specified in the ProxyPass line.
       ProxyPreserveHost On
       ProxyPass        "/" "https://127.0.0.1:14443/"
       ProxyPassReverse "/" "https://127.0.0.1:14443/"

       # Self signed SSL Certificate file
       SSLCertificateFile /etc/letsencrypt/live/app.com.co/fullchain.pem
       SSLCertificateKeyFile /etc/letsencrypt/live/app.com.co/privkey.pem
       Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

码头工人-compose.yml

version: '3.8'

services:
  nginx:
    build: ./nginx
    ports:
      - 1300:80
      - 14443:443
    depends_on:
      - backend
    networks:
      - backend-tier

  backend:
    expose:
      - 8000
    build:
      context: .
      dockerfile: ./Dockerfile
    restart: unless-stopped
    networks:
      - backend-tier
    depends_on:
      - db
      - redis
    volumes:
      - ./app_com_co/:/app/app_com_co:Z
      - ./app_com_co/templates/:/app/app_com_co/templates:Z
      # shared volume between worker, beat and backend for media
      - app-media:/app/app_com_co/media
    env_file: common.env

  db:
    image: library/postgres:11.1-alpine
    ports:
      - 5439:5432
    restart: unless-stopped
    networks:
      - backend-tier
    volumes:
      - app-db:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_DB=mydb

  redis:
    image: library/redis:5.0-alpine
    ports:
      - 6379:6379
    restart: unless-stopped
    networks:
      - backend-tier
    volumes:
      - app-redis:/data

  worker:
    build:
      context: .
      dockerfile: ./Dockerfile
    command: celery -A config --app=config.celery_app:app worker --loglevel=info
    restart: unless-stopped
    networks:
      - backend-tier
    env_file: common.env
    depends_on:
      - redis
    volumes:
      - ./app_com_co/:/app/app_com_co:Z,cached
      - ./app_com_co/templates/:/app/app_com_co/templates:Z,cached
      # shared volume between worker, beat and backend for media
      - app-media:/app/app_com_co/media

  beat:
    build:
      context: .
      dockerfile: ./Dockerfile
    command: celery -A config --app=config.celery_app:app beat --loglevel=info
    restart: unless-stopped
    networks:
      - backend-tier
    env_file: common.env
    depends_on:
      - redis
    volumes:
      - ./app_com_co/:/app/app_com_co:Z,cached
      - ./app_com_co/templates/:/app/app_com_co/templates:Z,cached
      # shared volume between worker, beat and backend for media
      - app-media:/app/app_com_co/media

volumes:
  app-db:
    driver: local
  app-redis:
    driver: local
  app-media:

networks:
  backend-tier:
    driver: bridge

Docker 容器内的 Nginx 配置

我不确定如何在 Docker 容器内的 Nginx 中配置 HTTPS 连接以接收来自 Apache 的 https 请求,然后重定向到 DJango 应用程序。

upstream django {
    server backend:8000;
}

server {
    listen 80;

    location / {
        proxy_pass http://django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        client_max_body_size 4G;
    }
}

标签: dockerapachenginxdocker-composecertbot

解决方案


尽量让你的容器保持无状态,所以不要在容器内使用 certbot。而是将 certbot 用于 Apache 或您在应用程序容器之外拥有的任何 Web 服务器。

可以让 Apache 以纯 HTTP 与您的应用程序容器对话,因为您的容器不会暴露给公共网络(确保它只接受 localhost 连接)。许多人采取了更简单的方法并将 Cloudflare 用于 SSL,这意味着从 http 到 https 的切换发生在离最终用户更近的地方。

注意:这种让反向代理处理 SSL 而不是您的应用程序的方法称为“SSL 终止”。


推荐阅读