Захотелось сделать для рабочих проектов ssl. Не самоподписной, не платный (сейчас бы в 2018 году за воздух платить), а нормальный бесплатный, от letsencrypt. И чтобы он автоматически продлялся (ибо срок его действия лишь 3 месяца).
Благо, все уже изобретено до нас.
Для развертывания сайта у меня был голый debian с установленными docker и docker-compose (настроенными для выполнения от рядового пользователя).
Сначала создаем docker-compose.yml, описывающий запуск небезывестной связки jwilder/nginx-proxy (реверс-прокси на nginx) и jrcs/letsencrypt-nginx-proxy-companion (certbot по сути). В добавок к ним я добавил популярный portainer/portainer, чтобы можно было мониторить, что происходит с контейнерами, и управлять ими из удобного веб-интерфейса.
Содержимое файла:
Доменное имя для portainer указано для примера. Единственное условия - чтобы оно было доступно извне для сервисов letsencrypt.
Уже по коду этого файла видно, как примерно работает эта связка. Если запустить ее
подождать, пока сгенерируется сертификат (обычно около 1-2 минут), то можно уже заходить по адресу, который мы указали в переменной VIRTUAL_HOST и увидеть работающий portainer. Причем уже по протоколу ssl. Если нажать на зеленый замочек, то мы увидим, что это действующий сертификат от letsencrypt.
Далее можно создавать контейнеры с помощью портейнера, а можно пойти более "простым" путем. Принцип подключения сайтов к виртуальной сети, в которой крутится reverse-proxy и certbot, остается тот же - использование переменных VIRTUAL_HOST, LETSENCRYPT_HOST и LETSENCRYPT_EMAIL.
Например, это простенький docker-compose.yml, описывающий связку сервисов для запуска битрикса:
и соответствующий ему .env файлик:
База хранится на хосте в .volume/db, мемкэш - в .volume/cache, сайт в www. Как-то так.
После чего, делаем запуск этих сервисов
Ждем, пока сгенерируется сертификат для новоиспеченного сайта, скачаются и соберутся образы, запустятся контейнеры, и можно открывать сайт в браузере (предварительно конечно прописав в .settings.php подключение к БД, где хостом будет название сервиса, в вышеприведенном случае - db; а параметрами подключения - значения из переменных .env-файлика).
И этот сайт сразу будет доступен по https с сертификатом от letsencrypt.
Алгоритм этой связки достаточно прост. В общих чертах если, то сервис nginx-proxy следит за появлением в сети новых сервисов с переменной VIRTUAL_HOST, и создает для них конфигурации server, подключает и запускает. Что позволяет пробиться к сервисам сквозь прокси.
Помощник letsencrypt таким же образом следит за сервисами с переменными LETSENCRYPT_ и генерирует для них сертификаты на соответствующее доменное имя. Попутно он дописывает конфигурации server у nginx-proxy, чтобы обеспечить подключение этих самых сертификатов и работу по https. Плюс, раз в час этот помощник проверяет, не устарели ли сертификаты, и генерирует их по новой, если надо.
Благо, все уже изобретено до нас.
Для развертывания сайта у меня был голый debian с установленными docker и docker-compose (настроенными для выполнения от рядового пользователя).
Сначала создаем docker-compose.yml, описывающий запуск небезывестной связки jwilder/nginx-proxy (реверс-прокси на nginx) и jrcs/letsencrypt-nginx-proxy-companion (certbot по сути). В добавок к ним я добавил популярный portainer/portainer, чтобы можно было мониторить, что происходит с контейнерами, и управлять ими из удобного веб-интерфейса.
// Предварительно создадим сеть $ docker network create nginx-proxy // Заведем для всей этой кухни свою папочку, для удобства я назвал и сеть, и контейнер, и директорию одинаково. $ mkdir nginx-proxy $ cd nginx-proxy // Для хранения сертификатов и некоторых автогенерируемых цертботом файлов нам потребуется пара директорий $ mkdir certs $ mkdir vhost.d // собственно файлик с описанием сервисов $ touch docker-compose.yml |
Содержимое файла:
version: "2" services: nginx-proxy: image: jwilder/nginx-proxy container_name: nginx-proxy labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy" # такой лейбл позволит контейнеру с цертботом понять, какой из запущенных nginx - реверс-прокси. ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro - ./vhost.d:/etc/nginx/vhost.d:ro - /usr/share/nginx/html letsencrypt-companion: image: jrcs/letsencrypt-nginx-proxy-companion container_name: letsencrypt-companion volumes_from: - nginx-proxy volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./certs:/etc/nginx/certs:rw - ./vhost.d:/etc/nginx/vhost.d:rw portainer: image: portainer/portainer container_name: portainer ports: - 9000 volumes: - /var/run/docker.sock:/var/run/docker.sock - /opt/portainer/data:/data environment: - VIRTUAL_HOST=portainer.devserver.com - VIRTUAL_PORT=9000 - LETSENCRYPT_HOST=portainer.devserver.com - LETSENCRYPT_EMAIL=admin@devserver.com # по умолчанию подключаем к сети, в которой будут находиться будущие сайты networks: default: external: name: nginx-proxy |
Доменное имя для portainer указано для примера. Единственное условия - чтобы оно было доступно извне для сервисов letsencrypt.
Уже по коду этого файла видно, как примерно работает эта связка. Если запустить ее
$ docker-compose up -d |
Далее можно создавать контейнеры с помощью портейнера, а можно пойти более "простым" путем. Принцип подключения сайтов к виртуальной сети, в которой крутится reverse-proxy и certbot, остается тот же - использование переменных VIRTUAL_HOST, LETSENCRYPT_HOST и LETSENCRYPT_EMAIL.
Например, это простенький docker-compose.yml, описывающий связку сервисов для запуска битрикса:
version: '2.1' # сеть по умолчанию - та же, что и сеть реверса и цертбота networks: default: external: name: nginx-proxy ### Services services: nginx: image: nginx:${NGINX_VERSION} container_name: ${PROJECT_CODE}_nginx environment: - VIRTUAL_HOST=$PROJECT_DOMAIN - LETSENCRYPT_HOST=$PROJECT_DOMAIN - LETSENCRYPT_EMAIL=$PROJECT_EMAIL volumes: - "${PROJECT_PATH}:/var/www/html/:ro" ## тут можно пробросить в контейнер нужные вам конфиги, например правильно указанный upstream - "./nginx/project.conf:/etc/nginx/sites-available/project.conf:ro" - "./nginx/upstream.conf:/etc/nginx/conf.d/upstream.conf:ro" links: - php php: image: alterway/php:${PHP_VERSION}-${BACKEND} container_name: ${PROJECT_CODE}_php environment: - PHP_php5enmod=mcrypt memcached mysqli opcache gd mbstring soap zip - PHP__date.timezone - PHP__display_errors - PHP__log_errors - PHP__magic_quotes_gpc - PHP__memory_limit - PHP__upload_max_filesize - PHP__post_max_size - PHP__max_execution_time - PHP__mbstring.func_overload - PHP__mbstring.internal_encoding - PHP__opcache.enable - PHP__opcache.revalidate_freq - PHP__opcache.validate_timestamps - PHP__opcache.memory_consumption - PHP__opcache.max_accelerated_files - PHP__realpath_cache_size - PHP__max_input_vars volumes: - "${PROJECT_PATH}/:/var/www/html/" db: image: mysql:${MYSQL_VERSION} container_name: ${PROJECT_CODE}_db volumes: ## это чтобы не потерять базу после перезапуска контейнера - "${VOLUMESDIR}/db/:/var/lib/mysql/" ## тут можно пробросить в контейнер нужные конфиги и прочее environment: MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} memcached: image: memcached:${MEMCACHED_VERSION} container_name: ${PROJECT_CODE}_mem volumes: ## это чтобы не потерять кэш после перезапуска контейнера - "${VOLUMESDIR}/cache/:/var/lib/memcached/" |
## Project settings PROJECT_CODE=mynewsite PROJECT_DOMAIN=mynewsite.ru PROJECT_EMAIL=admin@mynewsite.ru PROJECT_REPO=yournamespace PROJECT_MAINTAINER=Your Name <yourname@youremail.com> PROJECT_PATH=./www VOLUMESDIR=./.volume ## Services versions ## NGINX_VERSION=latest PHP_VERSION=5.6 # fpm or apache BACKEND=apache MYSQL_VERSION=5.6 MEMCACHED_VERSION=latest ## MYSQL MYSQL_DATABASE=project_database MYSQL_USER=project_user MYSQL_PASSWORD=project_p@sZw0rd MYSQL_ROOT_PASSWORD=root ## Bitrix php specific settings PHP__date.timezone=Europe/Moscow PHP__display_errors=On PHP__log_errors=On PHP__magic_quotes_gpc=Off PHP__memory_limit=128M PHP__upload_max_filesize=50M PHP__post_max_size=50M PHP__max_execution_time=60 PHP__mbstring.func_overload=2 PHP__mbstring.internal_encoding='UTF-8' PHP__opcache.enable=1 PHP__opcache.revalidate_freq=0 PHP__opcache.validate_timestamps=1 PHP__opcache.memory_consumption=64 PHP__opcache.max_accelerated_files=100000 PHP__realpath_cache_size=4096k PHP__max_input_vars=10000 |
После чего, делаем запуск этих сервисов
$ docker-compose up -d |
И этот сайт сразу будет доступен по https с сертификатом от letsencrypt.
Алгоритм этой связки достаточно прост. В общих чертах если, то сервис nginx-proxy следит за появлением в сети новых сервисов с переменной VIRTUAL_HOST, и создает для них конфигурации server, подключает и запускает. Что позволяет пробиться к сервисам сквозь прокси.
Помощник letsencrypt таким же образом следит за сервисами с переменными LETSENCRYPT_ и генерирует для них сертификаты на соответствующее доменное имя. Попутно он дописывает конфигурации server у nginx-proxy, чтобы обеспечить подключение этих самых сертификатов и работу по https. Плюс, раз в час этот помощник проверяет, не устарели ли сертификаты, и генерирует их по новой, если надо.