Перейти к содержимому
Главная страница » Caddy в Docker

Caddy в Docker

Что такое Caddy?

Caddy — это мощный веб-сервер с открытым исходным кодом, готовый к работе в корпоративных сетях, с автоматическим подключением HTTPS, написанный на Go. Caddy известен как самый продвинутый HTTPS-сервер в мире. Caddy рекомендуют многие эксперты, данный веб-сервер предлагает широкий набор функций и уникальный и упрощённый подход к настройке веб-сервера, что отличает его от предшественников, таких как Apache или Nginx.

Благодаря автоматической настройке HTTPS и простой в использовании конфигурации Caddyfile вам не придётся изучать ещё один сложный язык конфигурации или разбираться в сложном управлении сертификатами TLS. Кроме того, встроенная в Caddy поддержка  HTTP/3 делает его высокоэффективным и перспективным решением для развёртывания веб-приложений.

Запуск Caddy в Docker

Самый простой способ начать работу с Caddy-сервером — использовать официальный образ Docker и запустить Caddy в качестве контейнера Docker. Это обеспечивает бесперебойный процесс установки, который также довольно просто воспроизвести в разных системах.

Для начала выполните следующую команду:

docker run --rm -p 80:80 caddy

Caddy станет доступен, как только вы увидите следующее сообщение в своём терминале:

 Выходной сигнал

{"level":"info","ts":1699614997.5182397,"msg":"serving initial configuration"}

Затем вы можете открыть http://localhost в своём браузере, и вы увидите страницу по умолчанию «Caddy works!», которая указывает на то, что он запущен и готов обрабатывать веб-трафик:

Это все, что нужно для начала работы.

Выполненная вами команда docker run запустила новый контейнер Docker с Caddy. Он также сопоставил порт 80 на вашем локальном компьютере с портом 80 в контейнере, чтобы сервер стал доступен в вашем браузере по адресу http://localhost.

Флаг --rm указывает движку Docker удалить контейнер, как только вы закончите с ним работать, чтобы ваша система оставалась чистой во время экспериментов с различными настройками конфигурации, которые вы собираетесь изучить.

Я намеренно не указал флаг -d в команде, чтобы контейнер оставался запущенным в режиме переднего плана. Так вам будет проще изучить журналы, которые создаются при запуске, поскольку в них содержится ценная информация о том, как устроен образ Docker по умолчанию.

Давайте посмотрим на логи. В самой первой строке написано:

 Выходной сигнал

{"level":"info","ts":1699254136.4679956,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}

Это означает, что экземпляр сервера Caddy, работающий внутри контейнера, загружает свою конфигурацию из любого файла, подключённого к /etc/caddy/Caddyfile. Образ поставляется с конфигурацией по умолчанию Caddyfile, содержащей минимальные настройки, необходимые для начала работы. Чтобы изменить её, вы можете подключить собственный файл конфигурации к /etc/caddy/Caddyfile, заменив файл по умолчанию.

Парой строк ниже вы можете увидеть:

 Выходной сигнал

{"level":"warn","ts":1699254136.4689212,"logger":"http.auto_https","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv0","http_port":80}

Это означает, что поставляемый Caddyfile по умолчанию не поддерживает HTTPS. Поэтому вам нужно изменить конфигурацию, чтобы включить TLS, как вы увидите сейчас.

Наконец, есть сообщения:

 Выходной сигнал

{"level":"info","ts":1699254136.4690306,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}

 Выходной сигнал

{"level":"info","ts":1699254136.4692078,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}

Из них следует, что Caddy хранит данные во время выполнения, такие как сертификаты TLS, закрытые ключи и скрепы OCSP, в папке /data и сохраняет последнюю конфигурацию в папке /config внутри работающего контейнера.

Такие данные не предназначены для краткосрочного хранения, поэтому я настоятельно рекомендую использовать для этих папок подключённые тома, чтобы не потерять конфигурацию и не выпускать новые SSL-сертификаты при каждом перезапуске контейнера.

Учитывая всё вышесказанное, можно сделать вывод, что нет необходимости изменять исходный образ Docker, чтобы адаптировать контейнер Caddy под ваши конкретные нужды.

Всё это можно сделать во время выполнения программы, создав правильный набор docker команд для запуска контейнера. Поскольку выполнение отдельных docker команд может оказаться трудоёмким и чреватым ошибками процессом, для оптимизации этого процесса предпочтительнее использовать такой инструмент, как Docker Compose.

Нажмите Ctrl+C, чтобы остановить контейнер Caddy и вернуться в командную строку. Вы должны увидеть что-то вроде:

 Выходной сигнал

^C{"level":"info","ts":1699609912.4189968,"msg":"shutting down","signal":"SIGINT"}
{"level":"warn","ts":1699609912.419042,"msg":"exiting; byeee!! 👋","signal":"SIGINT"}
{"level":"info","ts":1699609912.419472,"logger":"http","msg":"servers shutting down with eternal grace period"}
{"level":"info","ts":1699609912.4202948,"logger":"admin","msg":"stopped previous server","address":"localhost:2019"}
{"level":"info","ts":1699609912.4203057,"msg":"shutdown complete","signal":"SIGINT","exit_code":0}

Давайте быстро создадим новую папку и cd в ней, чтобы создать черновик docker-compose.yml и пользовательский Caddyfile:

mkdir caddy-tutorial && cd caddy-tutorial

Создайте новый файл Caddyfile следующего содержания:

Файл Caddyfile

:80 {
    root * /usr/share/caddy
    file_server
}

Эта конфигурация указывает Caddy искать папку /usr/share/caddy внутри контейнера Docker для файла index.html и предоставлять этот файл по протоколу HTTP.

Создайте следующий фиктивный index.html файл:

index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>Hello, Caddy!</title>
</head>
<body>
    <p>Hello, Caddy!</p>
</body>
</html>

Идея состоит в том, чтобы подключить этот файл к /usr/share/caddy для отображения его содержимого при открытии http://localhost в браузере.

Наконец, создайте docker-compose.yml:

docker-compose.yml

version: '3'

name: caddy-tutorial

services:
  caddy:
    container_name: caddy
    image: caddy
    restart: always
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - caddy-config:/config
      - caddy-data:/data
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./index.html:/usr/share/caddy/index.html

volumes:
  caddy-config:
  caddy-data:

Этот файл немного длиннее остальных, но его содержимое простое. Он определяет два постоянных тома с именами caddy-config и caddy-data, подключая их к папкам /config и /data внутри контейнера Caddy для сохранения состояния вашего веб-сервера.

Кроме того, он монтирует Caddyfile и index.html файлы, которые вы только что создали, в соответствующие папки внутри контейнера. Наконец, он открывает порты 80 и 443 для доступа к вашему веб-серверу на localhost через HTTP и HTTPS соответственно.

Перечислите содержимое вашей текущей папки:

ls -l

Если все правильно, вы должны увидеть следующие файлы:

 Выходной сигнал

total 12
-rw-rw-r-- 1 marin marin 164 Nov 10 13:03 Caddyfile
-rw-rw-r-- 1 marin marin 302 Nov 10 13:05 docker-compose.yml
-rw-rw-r-- 1 marin marin 188 Nov 10 13:04 index.html

Теперь вы можете запустить контейнер Caddy с помощью Docker Compose:

docker compose up -d

 Выходной сигнал

[+] Running 1/1
 ✔ Container caddy-tutorial-caddy-1  Started

Теперь снова откройте http://localhost и вы увидите «Привет, Кэдди!»:

Если по какой-то причине при запуске docker compose up вместо этого вы видите сообщение об ошибке, убедитесь, что никакие другие запущенные приложения не используют порты 80 или 443:

 Выходной сигнал

Error response from daemon: driver failed programming external connectivity on endpoint caddy (b555101cb58677dc7e017d23747f326a978a6ea920955d3131432d700a5e843f): Bind for 0.0.0.0:80 failed: port is already allocated

На этом этапе всё должно работать правильно, и вы можете закрыть контейнер Caddy, прежде чем продолжить:

docker compose down

 Выходной сигнал

[+] Running 2/2
 ✔ Container caddy-tutorial-caddy-1  Removed    0.4s
 ✔ Network caddy-tutorial_default    Removed    0.4s

Настройка HTTPS с помощью Caddy

Одна из самых крутых функций Caddy — это возможность автоматически подготавливать и продлевать сертификаты TLS после небольшой первоначальной настройки. Это избавляет от необходимости запоминать сложные команды или проходить длительный процесс проверки для получения и установки сертификатов.

Объявив своё доменное имя внутри Caddyfile, Caddy берёт на себя все подготовительные работы и выполняет их автоматически.

Чтобы понять, как это работает на практике, вам нужно владеть доменным именем. В этой статье мы будем называть доменное имя, которым вы владеете, <your_domain_name>. Чтобы следовать приведенным ниже примерам, замените <your_domain_name> на фактическое доменное имя, которым вы владеете (например, example.com).

Укажите <your_domain_name> на компьютер, на котором работает ваш контейнер Caddy, убедившись, что брандмауэры не блокируют трафик на портах 80 и 443 (например, если вы находитесь за маршрутизатором, убедитесь, что порты 80 и 443 открыты и трафик правильно перенаправляется на ваш компьютер).

Чтобы убедиться в этом, запустите сервер Caddy и попробуйте получить к нему доступ через ваше доменное имя:

docker compose up -d

Если настройки DNS и сети верны, вы должны увидеть страницу «Привет, Caddy!» при вводе <your_domain_name> в браузере:

Прежде чем приступить к настройке сертификата, стоит обратить внимание на состояние папки /data внутри контейнера Caddy. Чтобы вывести её содержимое, выполните следующую команду:

docker container exec caddy ls -l /data/caddy

 Выходной сигнал

total 0

Вы видите, что папка /data/caddy в данный момент пуста. Это изменится в ближайшее время, когда будет создан сертификат TLS.

Идите вперед и остановите контейнер:

docker compose down

Затем измените Caddyfile следующим образом:

Файл Caddyfile

<your_domain_name> {
    root * /usr/share/caddy
    file_server
}

Здесь вы просто заменяете привязку :80 на полное имя вашего домена. Теперь вы можете перезапустить контейнер Caddy, но на этот раз без флага -d для просмотра журналов, создаваемых в процессе подготовки сертификата.

docker compose up

После инициализации сервера вы увидите следующий набор сообщений, указывающих на то, что был создан новый сертификат:

 Выходной сигнал

caddy  | {"level":"info","ts":1699618884.7067113,"logger":"tls.obtain","msg":"acquiring lock","identifier":"<your_domain_name>"}
caddy  | {"level":"info","ts":1699618884.7076728,"logger":"tls.obtain","msg":"lock acquired","identifier":"<your_domain_name>"}
caddy  | {"level":"info","ts":1699618884.707749,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"<your_domain_name>"}
caddy  | {"level":"info","ts":1699618884.7086315,"logger":"http","msg":"waiting on internal rate limiter","identifiers":["<your_domain_name>"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy  | {"level":"info","ts":1699618884.7086391,"logger":"http","msg":"done waiting on internal rate limiter","identifiers":["<your_domain_name>"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy  | {"level":"info","ts":1699618885.8201177,"logger":"http.acme_client","msg":"authorization finalized","identifier":"<your_domain_name>","authz_status":"valid"}
caddy  | {"level":"info","ts":1699618885.8201704,"logger":"http.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/1406393766/221214636416"}
caddy  | {"level":"info","ts":1699618886.933485,"logger":"http.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/0439041a395e765fd31f5cd2b7d1e92fe056"}
caddy  | {"level":"info","ts":1699618886.9343963,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"<your_domain_name>"}
caddy  | {"level":"info","ts":1699618886.9346375,"logger":"tls.obtain","msg":"releasing lock","identifier":"<your_domain_name>"}

Теперь, если вы попытаетесь открыть <your_domain_name> в браузере, вы увидите, что страница «Привет, Caddy!» успешно загрузилась по протоколу HTTPS:

Здесь ваш экземпляр Caddy связался с центром сертификации Let’s Encrypt, получил новый сертификат и установил его на веб-сервере.

Прежде чем выключить контейнер, откройте новый терминал и ещё раз проверьте содержимое папки /data/caddy в контейнере.

docker container exec caddy ls -l /data/caddy

 Выходной сигнал

total 16
drwx------  3 root  root    4096 Nov 10 12:20 acme
drwx------  3 root  root    4096 Nov 10 12:21 certificates
drwx------  2 root  root    4096 Nov 10 12:21 locks
drwx------  2 root  root    4096 Nov 10 12:21 ocsp

Как видите, папка больше не пустая. Она содержит все необходимые файлы для выдачи, подготовки и продления сертификатов.

Помимо выдачи новых сертификатов, Caddy также автоматически продлевает сертификаты в фоновом режиме, избавляя вас от необходимости вручную продлевать сертификаты или беспокоиться о сроках их действия.

Пока Caddy работает, для каждого сертификата запускается процесс обновления, как только срок его действия подходит к концу. Caddy автоматически загружает, устанавливает и активирует новый сертификат, не прекращая обслуживать запросы, поэтому у ваших клиентов не будет простоев.

При установке сертификата TLS Caddy также автоматически перенаправляет весь HTTP-трафик на конечную точку HTTPS, обеспечивая безопасность всех соединений между клиентом и сервером по умолчанию.

Перевод инструкции: Deploying Web Apps with Caddy: A Beginner’s Guide

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *