Что такое 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