---
title: "HTTPS для IP-адреси через Let's Encrypt у FrankenPHP"
url: https://laravelukraine.com/blog/https-dlia-ip-adresi-cerez-lets-encrypt-u-frankenphp
date: 2026-08-19
source: https://laravel-news.com/frankenphp-https-ip-address?utm_medium=feed&utm_source=feedpress.me&utm_campaign=Feed%3A+laravelnews
---

# HTTPS для IP-адреси через Let's Encrypt у FrankenPHP

Docker-образи `serversideup/php`, що розробляються в репозиторії [serversideup/docker-php](https://github.com/serversideup/docker-php), отримали версію v4.6.0-beta1 зі змінною `CADDY_ACME_PROFILE`, яка дозволяє вибрати профіль `shortlived` (короткотривалий) від Let's Encrypt. Це єдиний профіль, під яким Let's Encrypt видає сертифікати для IP-адрес, тому FrankenPHP-контейнер, доступний лише по IP, тепер може обслуговувати справжній HTTPS без жодного DNS.

[Jay Rogers](https://github.com/jaydrogers) із Server Side Up [анонсував](https://x.com/jaydrogers/status/2085012766146822148) цю можливість разом із бета-версією:

> Я працював над цим досить довго і нарешті налаштував:
>
> 🔐 HTTPS для IP-адрес
>
> Це величезний прорив для тих, хто розгортає власні сервери. Не потрібен DNS. Все працює на Let's Encrypt + FrankenPHP.

## Для кого це корисно

Ті, хто розгортає власні сервери (self-hosters), - найочевидніший випадок використання, але та сама проблема зустрічається в багатьох командних сетапах: staging-сервер, піднятий на тиждень; внутрішнє API за VPN; демонстраційний сервер для клієнта; дашборд черг на droplet. Усі вони можуть бути доступні по IP задовго до того, як хтось вирішить питання з hostname. До цього моменту це означало самопідписаний сертифікат із попередженням браузера або reverse proxy з реальним сертифікатом.

Let's Encrypt зробив [загальнодоступними](https://letsencrypt.org/2026/01/15/6day-and-ip-general-availability) 6-денні сертифікати та сертифікати для IP-адрес у січні. Caddy реалізує вибір профілю сертифікатів та ідентифікатори IP, а FrankenPHP вбудовує Caddy (наразі v2.11.4). Ця бета-версія додає змінну оточення та Caddyfile-сніпети, які Caddy імпортує залежно від її значення.

## Як працює короткотривалий профіль

`CADDY_ACME_PROFILE` за замовчуванням має значення `off` і приймає `shortlived`, `tlsserver` або `classic`. Встановіть значення `shortlived`, і Caddy запитуватиме сертифікати терміном дії 160 годин (трохи менше семи днів), оновлюючи їх кожні два дні.

Такий термін дії відповідає визначенню Short-Lived Subscriber Certificate від CA/Browser Forum. Згідно з [документацією профілів](https://letsencrypt.org/docs/profiles/) Let's Encrypt, такі сертифікати «не повинні містити інформацію про відкликання». Однак профіль shortlived все ще вказує на certificate revocation list (CRL) - опублікований запис сертифікатів, які центр сертифікації анулював достроково, і це може змінитися. За такого терміну дії відкликання має менше значення, оскільки скомпрометований ключ перестає бути корисним через дні, а не місяці.

Встановлення змінної записує невеликий Caddyfile-сніпет у конфігурацію:

```
cert_issuer acme {
  profile shortlived
}
```

Let's Encrypt вимагає той самий профіль для сертифікатів IP-адрес, тому обидві функції з'явилися в одній змінній. Встановлення будь-якого профілю для Let's Encrypt прибирає резервний варіант ZeroSSL, який образи інакше зберігають. Оновлення кожні два дні також залишає менше запасу, якщо контейнер втратить вихідний доступ до ACME API Let's Encrypt - інтерфейсу, який Caddy використовує для запиту та оновлення сертифікатів. Після зміни файрволу, яка блокує egress, у вас є чотири з половиною дні, щоб помітити проблему до закінчення терміну дії сертифіката, тоді як 90-денний сертифікат залишив би вам тижні.

## Налаштування

Функція доступна лише в бета-тегах, тому закріпіть образ на бета-версії, а не на стабільному тезі `8.4-frankenphp`. Документація пропонує Docker Compose конфігурацію, близьку до цієї:

```yaml
services:
  php:
    image: serversideup/php:8.4-frankenphp-v4.6.0-beta1
    ports:
      - "80:8080"
      - "443:8443"
    volumes:
      - caddy-config:/config
      - caddy-data:/data
    environment:
      SSL_MODE: "full"
      CADDY_AUTO_HTTPS: "on"
      CADDY_ACME_PROFILE: "shortlived"
      CADDY_HTTPS_SERVER_ADDRESS: "https://203.0.113.10"
      CADDY_GLOBAL_OPTIONS: "default_sni example.com"
      
volumes:
  caddy-config:
  caddy-data:
```

`CADDY_AUTO_HTTPS` вмикає автоматичний HTTPS у Caddy; за замовчуванням він вимкнений. `SSL_MODE: "full"` обслуговує застосунок через HTTPS і надсилає HTTP-трафік туди з кодом 308. `CADDY_HTTPS_SERVER_ADDRESS` - сюди вказується IP-адреса. Контейнер слухає на портах 8080 і 8443, оскільки працює без привілеїв; звідси маппінг портів, і обидва мають бути доступні з інтернету, щоб ACME-челендж пройшов успішно.

Браузер, відкриваючи TLS-з'єднання, зазвичай оголошує hostname, який він запитує - поле під назвою Server Name Indication (SNI), і саме так сервер із кількома сертифікатами вибирає потрібний. Клієнт, що підключається до IP-адреси, не надсилає SNI, оскільки немає імені для відправки, тому Caddy нічого не має для зіставлення з сертифікатом. `CADDY_GLOBAL_OPTIONS: "default_sni example.com"` надає резервну ідентичність для таких з'єднань.

## Підтримка IPv6 та обережності

Якщо вам потрібно це через IPv6, протестуйте перед покладанням на це. Caddy виправив обробку IPv6 для IP-сертифікатів пізніше за підтримку IPv4, у [issue #7399](https://github.com/caddyserver/caddy/issues/7399), який закрили в квітні. Caddy v2.11.4 вийшов після цього виправлення, тому поточні образи мають його, але IPv4 працює довше.

Також змонтуйте `/config` і `/data` на volumes. Сертифікати та стан ACME-акаунта зберігаються там, і контейнер, що втрачає їх при кожному перезапуску, запитуватиме нові сертифікати при кожному перезапуску. Let's Encrypt дозволяє п'ять сертифікатів для ідентичного набору ідентифікаторів кожні сім днів, поповнюючи один кожні 34 години, тому кілька редеплоїв можуть вичерпати тиждень.

## Інші можливості v4.6.0-beta1

В інших частинах v4.6.0-beta1 змінна `TRUSTED_PROXY` тепер поводиться однаково для FrankenPHP, NGINX та Apache, тому `request()->ip()` повертає відвідувача, а не проксі, незалежно від варіанта, на якому працює застосунок. Вона приймає `cloudflare` (за замовчуванням), `sucuri`, `local` або `off`, і кожне значення, крім `off`, довіряє внутрішнім діапазонам Docker поряд із CDN, тому робота за Cloudflare та Traefik-контейнером одночасно не потребує додаткової конфігурації. FrankenPHP також постачається з директорією `caddyfile-global.d`, куди ви можете додавати власну глобальну конфігурацію.

Laravel Nightwatch включає скрипт `healthcheck-nightwatch`, що виконує `php artisan nightwatch:status`, тому ви можете направити `HEALTHCHECK` контейнера на агента. А `AUTORUN_LARAVEL_SKIP_IF_NOT_FOUND` дозволяє контейнеру з `AUTORUN_ENABLED=true` коректно завершитися, коли Laravel ще немає, наприклад, перед першим `composer install`, замість помилки.

v4.6.0-beta1 позначено як prerelease, тому тримайте його подалі від того, що ви не можете дозволити собі зламати, поки пробуєте IP-сертифікати. Повні примітки - на [сторінці релізу v4.6.0-beta1](https://github.com/serversideup/docker-php/releases/tag/v4.6.0-beta1), а налаштування задокументовано в розділі [configuring SSL](https://serversideup.net/open-source/docker-php/docs/deployment-and-production/configuring-ssl) документації Server Side Up. Якщо ви давно не дивилися на сам FrankenPHP, ми раніше цього року писали про [FrankenPHP v1.11.2](https://laravel-news.com/frankenphp-v1112-released-with-30-faster-cgo-40-faster-gc-and-security-patches), а ще раніше - про [підтримку FrankenPHP у Laravel Octane](https://laravel-news.com/frankenphp-octane-out-of-beta).
