Forked from dancheskus/Certbot и nginx, как обратный прокси в Docker.md
Last active
July 17, 2020 18:06
-
-
Save mitrofun/eaf88ac35e65da4c0e29d2edb246a1e2 to your computer and use it in GitHub Desktop.
Revisions
-
dancheskus revised this gist
Feb 5, 2019 . 1 changed file with 6 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,4 @@ # Certbot и nginx, как обратный прокси в Docker (пример с 2 react проектами) >В результате будет 2 react проекта на 1 сервере доступных по разным ссылкам @@ -206,16 +207,12 @@ networks: ``` ### Меняем `docker-compose` файл в `react` проекте В папке `proj1` в файле `docker-compose` удаляем ```yml ports: - 8080:5000 ``` >Контейнер по прежнему слушает на порту `5000`, но уже не открывает его для локального компьютера. Этот порт теперь доступен только контейнерам в той-же сети. Под блоком `services` пишем @@ -244,8 +241,6 @@ services: nginx_net: environment: - NODE_ENV=production networks: nginx_net: @@ -411,8 +406,6 @@ server { } ``` ## Этап 4. Завершаем настройку `docker-compose.yml` для `nginx` и `certbot` В `services -> nginx` добавляем @@ -487,4 +480,6 @@ curl -L https://raw.githubusercontent.com/dancheskus/nginx-docker-ssl/master/ini Выполнив последнюю команду в папке `nginx -> data` появятся новые папки с сертификатами необходимые для работы `nginx` и `certbot` Если в тестовом режиме все получилось, то ставим `staging=0` и повторяем процедуру. **Готово** > `docker-compose run --rm --entrypoint "certbot certificates" certbot` - позволяет проверить зарегистрированные сертификаты и узнать их срок годности. -
dancheskus revised this gist
Feb 5, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -472,7 +472,7 @@ networks: Находясь в папке `nginx` вводим ``` curl -L https://raw.githubusercontent.com/dancheskus/nginx-docker-ssl/master/init-letsencrypt.sh > init-letsencrypt.sh ``` Затем открываем полученный `init-letsencrypt.sh` и вписываем: - вместо `example.com` свои домены через пробел -
dancheskus revised this gist
Feb 5, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -472,7 +472,7 @@ networks: Находясь в папке `nginx` вводим ``` curl -L https://github.com/dancheskus/nginx-docker-ssl/blob/master/init-letsencrypt.sh > init-letsencrypt.sh ``` Затем открываем полученный `init-letsencrypt.sh` и вписываем: - вместо `example.com` свои домены через пробел -
dancheskus revised this gist
Feb 4, 2019 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -485,4 +485,6 @@ curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsen `sudo ./init-letsencrypt.sh` Выполнив последнюю команду в папке `nginx -> data` появятся новые папки с сертификатами необходимые для работы `nginx` и `certbot` Если в тестовом режиме все получилось, то ставим `staging=0` и повторяем процедуру. > `docker-compose run --rm --entrypoint "certbot certificates" certbot` - проверить зарегистрированные сертификаты и узнать их срок годности. -
dancheskus revised this gist
Feb 2, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -411,7 +411,7 @@ server { } ``` >**Важно**. Скрипт, который мы запустим позже, сохраняет все сертификаты в папку, которая называется как первое доменное имя, которое мы там указываем. Соответственно в любом `server` блоке, независимо от домена, пути `ssl_certificate` и `ssl_certificate_key` должны быть одинаковыми. В нашем случае они содержат путь к папке `proj1`. ## Этап 4. Завершаем настройку `docker-compose.yml` для `nginx` и `certbot` -
dancheskus revised this gist
Feb 1, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -54,7 +54,7 @@ FROM mhart/alpine-node:11 # Качаем node контейнер с docker hub RUN yarn global add serve # Устанавливаем serve для сервирования нашего проекта WORKDIR /app # Указываем главную папку в контейнере, в которой будет наш проект COPY package.json yarn.lock ./ -
dancheskus created this gist
Feb 1, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,488 @@ # Certbot и nginx, как обратный прокси в Docker (пример с 2 react проектами) >В результате будет 2 react проекта на 1 сервере доступных по разным ссылкам ## Цели - Запустить **nginx** в одном контейнере - Запустить **другие проекты** в других контейнерах - Научить **nginx** перенаправлять запросы с разных доменов на разные проекты - Получить **ssl** сертификаты для всех проектов - Убрать **www** из названия сайтов с помощью **nginx** ## Перед началом >Перед тем как начать, должно быть следующее - Ubuntu сервер с открытыми портами `80` и `443`. - Установленный `docker` и `docker-compose` на локальном компьютере и сервере. - Зарегистрированные доменные имена. В этом руководстве я буду использовать `proj1.com` и `proj2.com` для двух проектов. - Запись `A` для `proj1.com` и `proj2.com`, указывает на публичный IP адрес нашего сервера. - Запись `A` для `www.proj1.com` и `www.proj2.com`, указывает на публичный IP адрес нашего сервера. ## В этом руководстве будет использоваться - nodejs - create-react-app - yarn - docker - docker-compose ## В любой момент может понадобится - `docker ps` - список запущенных контейнеров - `docker network ls` - список всех активных и неактивных сетей созданных docker'ом - `docker system prune` - очистка всех **остановленных контейнеров** и **неиспользуемых сетей** - `docker-compose down` - выполняется из корня проекта. Останавливает запущенный контейнер. # Настройка на локальном компьютере ## Этап 1. Создаем 2 `react` проекта >В результате будет 2 простых проекта В любом удобном месте на локальном компьютере создаем `react` проект `proj1` и `proj2` `yarn create react-app proj1` `yarn create react-app proj2` По очереди запускаем каждый из проектов `yarn start` и вносим маленькие изменения, чтобы видеть отличия проектов. >Например в `src -> App.js` каждого проекта вместо `Edit <code>src/App.js</code> and save to reload.` (create-react-app версия 2.1.3) напишем `proj1` и `proj2` соответственно. ## Этап 2. Упаковываем каждый проект в контейнер >В результате каждый проект будет в отдельном контейнере. Все действия далее описываю только для одного проекта. Их нужно сделать для двух проектов. ### Пишем инструкции для запуска контейнера В корне проекта создаем `Dockerfile` >**Dockerfile** - это инструкция по созданию контейнера ```dockerfile FROM mhart/alpine-node:11 # Качаем node контейнер с docker hub RUN yarn global add serve # Устанавливаем serve для серверования нашего проекта WORKDIR /app # Указываем главную папку в контейнере, в которой будет наш проект COPY package.json yarn.lock ./ # Копируем файлы package.json и yarn.lock в папку, указанную выше (не забываем ./) RUN yarn # Устанавливаем зависимости COPY . . # Копируем остальные файлы проекта в главную папку RUN yarn build # Компилируем проект CMD serve -s /app/build # Серверуем проект из новой папки build (по умолчанию порт 5000) ``` Далее в корне проекта создаем `docker-compose.yml` >**docker-compose** - это инструкция по запуску контейнер(а/ов) ```yml version: '3.7' # Смотреть актуальную версию docker-compose синтаксиса на оф. сайте services: # Объявляем список сервисов proj1: # Указываем название сервиса container_name: proj1 # Указываем название контейнера (не обязательно) build: . # Запускаем Dockerfile из корня проекта environment: - NODE_ENV=production # ENV переменная production сообщит yarn, что не нужно качать зависимости для разработки, если такие имеются. ports: # Слева порт, который будет доступен на локальной машине. Справа - тот, к которому нужен доступ в контейнере. - 8080:5000 # 5000 - порт который по умолчанию открывает serve в Dockerfile ``` В корне проекта создаем `.dockerignore` >**.dockerignore** - это список исключаемых из копирования `COPY . .` файлов и папок в `Dockerfile` ``` .git node_modules build ``` ### Запускаем и проверяем контейнер Из корня проекта выполняем `docker-compose up` >При первом запуске будут выполняться все инструкции `Dockerfile`, что займет какое-то время. Дальнейшие запуски, при отсутствии изменений в проекте, будут проходить быстрее. Когда видим строку вида `proj1 | INFO: Accepting connections at http://localhost:5000`, можем проверить в браузере `localhost:8080`. Результатом должен быть `react` проект с надписью `proj1`. В командной строке нажимаем `ctrl+c`, чтобы выйти из контейнера и проверяем проект `proj2` ## Этап 3. Создаем 2 фейковых url для теста >В результате будет 2 адреса, каждый из которых будет вести на `localhost`. Нужно для дальнейшей настройки `nginx`. **Этот шаг можно пропустить и продолжать действия на сервере** В `hosts` файле на компьютере добавляем запись ``` 127.0.0.1 proj1.com 127.0.0.1 proj2.com ``` ## Этап 4. Создаем `nginx` контейнер >В результате будет `nginx` контейнер, который будет работать на `80` порту ### Создаем `docker-compose` для `nginx` В удобном месте создаем папку `nginx`. Затем в ней создаем файл `docker-compose.yml` ```yml version: '3.7' services: nginx: container_name: nginx image: nginx:latest # Вместо Dockerfile берем готовый nginx (:latest - последняя версия) с docker hub volumes: - ./data/nginx.conf:/etc/nginx/conf.d/default.conf ports: - 80:80 # Порт 80 будет доступен как в контейнере, так и снаружи. ``` >**volumes** - позволяет использовать файлы из локального компьютера не копируя их в контейнер. >В данном случае мы берем файл `nginx.conf` из папки `data`, который мы создадим дальше, в папке `nginx` на локальном компьютере и "говорим" контейнеру, что это файл который находится здесь `/etc/nginx/conf.d/default.conf` ### Создаем `nginx.conf` для `nginx` В папке `nginx` создаем папку `data` в которой создаем файл `nginx.conf` (название и путь должны соответствовать указанным в `docker-compose`) ```nginx server { return 301 http://google.com; } ``` >Самый простой `conf`, для проверки работы контейнера. ### Запускаем `nginx` контейнер В папке `nginx` выполняем `docker-compose up`. В браузере при переходе на `localhost` мы должны попадать на сайт google. >Останавливаем контейнер и переходим далее ## Этап 5. Связываем контейнеры между собой >В результате `nginx` контейнер сможет перенаправлять запросы в другие контейнеры. >Действия описанные далее для `proj1` нужно выполнять для каждого проекта. ### Меняем `docker-compose` файл в `nginx` проекте В папке `nginx` в файле `docker-compose` под блоком `services` пишем новый блок `networks` ```yml networks: # Блок для объявления внутренних docker сетей, которые запустятся с этим файлом nginx_net: # Название сети для этого контейнера name: nginx_net # Название сети для внешних контейнеров ``` В блоке `services` в подблок `nginx` добавляем ```yml networks: nginx_net: # Подключаемся к новой сети в этом контейнере ``` --- **Результат:** ```yml version: '3.7' services: nginx: container_name: nginx image: nginx:latest networks: nginx_net: volumes: - ./data/nginx.conf:/etc/nginx/conf.d/default.conf ports: - 80:80 networks: nginx_net: name: nginx_net ``` ### Меняем `docker-compose` файл в `react` проекте В папке `proj1` в файле `docker-compose` ```yml ports: - 8080:5000 ``` меняем на ```yml ports: - 5000 ``` >Контейнер по прежнему слушает на порту `5000`, но уже не открывает его для локального компьютера. Этот порт теперь доступен только контейнерам в той-же сети. Под блоком `services` пишем ```yml networks: nginx_net: external: true # Сообщает о том, что сеть nginx_net находится не в этом контейнере. ``` В блоке `services` в подблок `proj1` добавляем ```yml networks: nginx_net: ``` --- **Результат:** ```yml version: '3.7' services: proj1: container_name: proj1 build: . networks: nginx_net: environment: - NODE_ENV=production ports: - 5000 networks: nginx_net: external: true ``` ### Меняем `nginx.conf` файл Удаляем все, что писали для примера и пишем ```nginx server { server_name proj1.com; location / { resolver 127.0.0.11; set $project http://proj1:5000; proxy_pass $project; } } server { server_name proj2.com; location / { resolver 127.0.0.11; set $project http://proj2:5000; proxy_pass $project; } } ``` > Каждый блок `server` отвечает за отдельные задачи. > > `server_name` определяет с какого именно домена пришел запрос. > > `location /` указывает на то, что нас устраивает как `proj1.com`, так и что угодно после `/`. > > `proxy_pass` перенаправляет запрос на наш контейнер. **proj1** в `http://proj1:5000` доступен благодаря названию контейнера в `docker-compose -> services`. > > `resolver 127.0.0.11;` и `set $project http://proj1:5000;` нужны для того, чтобы контейнер мог запустится даже при нерабочем контейнере `proj1`. Можно было написать и `proxy_pass http://proj2:5000;` без переменных, но в этом случае, если не запущен контейнер `proj1`, `nginx` не запустится и выдаст ошибку. Запускаем все контейнеры `proj1`, `proj2` и `nginx`. В результате, вводя в браузере `proj1.com` и `proj2.com` мы попадаем на наши 2 проекта. ## Этап 6. Переносим контейнеры на сервер Если, все описанное выше работает, можно переносить наши проекты на сервер заменив все названия проектов, доменов в `nginx.conf` `proj1` и `proj2` на необходимые названия и домены. Для удобства я продолжу использовать `proj1` и `proj2`. В `nginx.conf` в `server_name` добавляем `www` записи. В итоге строка будет выглядеть так ```nginx server_name proj1.com www.proj1.com; ``` Убедившись, что на сервере все работает, можно приступать к следующей части. # Настройка на сервере >Далее, много информации берется [от сюда](https://medium.com/@pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71) ## Этап 1. Подключаем `certbot` контейнер для запуска с `nginx` >В результате в папке `nginx`, `docker-compose up` будет запускать 2 контейнера. `nginx` и `certbot` В `services -> nginx -> ports` добавляем ```yml - 443:443 # Открываем порты для ssl соединения ``` В `services` добавляем ```yml certbot: # Новый контейнер, который запуститься вместе с nginx container_name: certbot image: certbot/certbot # Образ берется с docker hub networks: nginx_net: # Подключаем к той-же сети, что и остальные контейнеры ``` >Если мы запустим контейнер сейчас, будет ошибка, так как `certbot `не может провести первичную настроку в docker контейнере. ## Этап 2. Добавляем пути к сертификатам >В конце мы запустим скрипт, который сгенерирует, сначала, фейковые сертификаты, для запуска `nginx`, а затем и настоящие. В этой части мы прописываем пути по которым `nginx` и `certbot` смогут их увидеть. В `services -> nginx` добавляем ```yml - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot ``` В `services -> certbot` добавляем ```yml volumes: - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot ``` --- **Результат** ```yml version: '3.7' services: nginx: container_name: nginx image: nginx:latest networks: nginx_net: volumes: - ./data/nginx.conf:/etc/nginx/conf.d/default.conf - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot ports: - 80:80 - 443:443 certbot: container_name: certbot image: certbot/certbot networks: nginx_net: volumes: - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot networks: nginx_net: name: nginx_net ``` ## Этап 3. Редактируем `nginx` >Здесь мы создаем финальную конфигурацию `nginx`. >В примере будет 1 `server` блок отвечающий за `proj1`. Соответственно, сколько проектов, столько и `server` блоков. Существует множество конфигураций `nginx`. Здесь приведена одна из них. ```nginx server { listen 80; listen 443 ssl; # Слушаем на портах 80 и 443 server_name proj1.com www.proj1.com; # Этот сервер блок выполняется при этих доменных именах ssl_certificate /etc/letsencrypt/live/proj1.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/proj1.com/privkey.pem; # ssl_certificate и ssl_certificate_key - необходимые сертификаты include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # include и ssl_dhparam - дополнительные, рекомендуемые Let's Encrypt, параметры # Определяем, нужен ли редирект с www на без www'шную версию if ($server_port = 80) { set $https_redirect 1; } if ($host ~ '^www\.') { set $https_redirect 1; } if ($https_redirect = 1) { return 301 https://proj1.com$request_uri; } location /.well-known/acme-challenge/ { root /var/www/certbot; } # Путь по которому certbot сможет проверить сервер на подлинность location / { resolver 127.0.0.11; set $project http://proj1:5000; proxy_pass $project; } } ``` >**Важно**. Скрипт, который мы запустим позже, сохраняет все сертификаты в папку, которая называется как первое доменное имя, которое мы там указываем. Соответственно в любом `server` блоке, независимо от домена пути `ssl_certificate` и `ssl_certificate_key` должны быть одинаковыми. В нашем случае они содержат путь к папке `proj1`. ## Этап 4. Завершаем настройку `docker-compose.yml` для `nginx` и `certbot` В `services -> nginx` добавляем ```yml restart: unless-stopped # Перезапустит контейнер в непредвиденных ситуациях command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"''' # Перезапустит nginx контейнер каждые 6 часов и подгрузит новые сертификаты, если есть ``` В `services -> certbot` добавляем ```yml restart: unless-stopped entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" # Проверяет каждые 12 часов, нужны ли новые сертификаты ``` --- **Результат** ```yml version: '3.7' services: nginx: container_name: nginx image: nginx:latest restart: unless-stopped networks: nginx_net: volumes: - ./data/nginx.conf:/etc/nginx/conf.d/default.conf - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot ports: - 80:80 - 443:443 command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"''' certbot: container_name: certbot image: certbot/certbot restart: unless-stopped #+++ networks: nginx_net: volumes: - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" networks: nginx_net: name: nginx_net ``` ## Этап 5. Получаем сертификаты Находясь в папке `nginx` вводим ``` curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh ``` Затем открываем полученный `init-letsencrypt.sh` и вписываем: - вместо `example.com` свои домены через пробел - email - меняем пути, если меняли их в папке - `staging` временно ставим 1 (для теста) `chmod +x init-letsencrypt.sh` `sudo ./init-letsencrypt.sh` Выполнив последнюю команду в папке `nginx -> data` появятся новые папки с сертификатами необходимые для работы `nginx` и `certbot` Если в тестовом режиме все получилось, то ставим `staging=0` и повторяем процедуру.