---
title: "Деплой в продакшен"
description: "В этом руководстве мы рассмотрим, как развернуть PHP-приложение на одном сервере с использованием Docker Compose."
sidebar:
  label: "Деплой в продакшен"
  order: 1
---
Если вы используете Symfony, рекомендуется прочитать раздел "[Deploy in production](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" документации проекта Symfony Docker (в котором используется FrankenPHP).

Если вы используете API Platform (который также использует FrankenPHP), ознакомьтесь с [документацией по развертыванию этого фреймворка](https://api-platform.com/docs/deployment/).

## Подготовка приложения

Сначала создайте файл `Dockerfile` в корневой директории вашего PHP-проекта:

```dockerfile
FROM dunglas/frankenphp

# Убедитесь, что вы заменили "your-domain-name.example.com" на ваше доменное имя
ENV SERVER_NAME=your-domain-name.example.com
# Если вы хотите отключить HTTPS, используйте это значение вместо:
#ENV SERVER_NAME=:80

# Если ваш проект не использует директорию "public" в качестве корневой веб-директории, вы можете указать её здесь:
# ENV SERVER_ROOT=web/

# Включите настройки PHP для продакшена
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Скопируйте PHP-файлы вашего проекта в публичную директорию
COPY . /app/public
# Если вы используете Symfony или Laravel, вам нужно скопировать весь проект вместо этого:
#COPY . /app
```

Ознакомьтесь с разделом "[Создание кастомных Docker-образов](/ru/docs/docker)" для получения дополнительных подробностей и опций, а также для установки PHP-расширений и модулей Caddy.

Если ваш проект использует Composer, убедитесь, что он включён в Docker-образ, и установите все зависимости.

Затем добавьте файл `compose.yaml`:

```yaml
services:
  php:
    image: dunglas/frankenphp
    restart: always
    ports:
      - "80:80" # HTTP
      - "443:443" # HTTPS
      - "443:443/udp" # HTTP/3
    volumes:
      - caddy_data:/data
      - caddy_config:/config

# Тома, необходимые для сертификатов и конфигурации Caddy
volumes:
  caddy_data:
  caddy_config:
```

<div class="fp-callout" data-callout="note">
<p class="fp-callout-title">Примечание</p>

Примеры выше предназначены для использования в продакшене.
В процессе разработки вы можете захотеть использовать том, другую конфигурацию PHP и другое значение для переменной окружения `SERVER_NAME`.

Посмотрите проект [Symfony Docker](https://github.com/dunglas/symfony-docker) (который использует FrankenPHP) для более сложного примера с использованием мультистейдж-образов, Composer, дополнительных PHP-расширений и т.д.

</div>

Наконец, если вы используете Git, закоммитьте эти файлы и отправьте их в репозиторий.

## Подготовка сервера

Для деплоя вашего приложения в продакшен вам потребуется сервер. В этом руководстве мы будем использовать виртуальную машину, предоставляемую DigitalOcean, но подойдёт любой Linux-сервер.
Если у вас уже есть Linux-сервер с установленным Docker, вы можете сразу перейти к [следующему разделу](#настройка-доменного-имени).

В противном случае, используйте [эту партнерскую ссылку](https://m.do.co/c/5d8aabe3ab80), чтобы получить $200 бесплатных кредитов, создайте аккаунт, затем нажмите "Create a Droplet".
Затем, нажмите на вкладку "Marketplace" в разделе "Choose an image" и найдите приложение "Docker". Это автоматически подготовит сервер Ubuntu с уже установленными последними версиями Docker и Docker Compose!

Для целей тестирования будет достаточно самых дешевых тарифных планов.
Для реального использования в продакшене вам, вероятно, захочется выбрать тарифный план из раздела "general purpose", соответствующий вашим потребностям.

![Деплой FrankenPHP на DigitalOcean с Docker](/blume-assets/content/content/assets/digitalocean-droplet.png)

Вы можете оставить остальные настройки по умолчанию или изменить их в соответствии с вашими потребностями. Не забудьте добавить свой SSH-ключ или создать пароль, затем нажмите кнопку "Finalize and create".

Затем подождите несколько секунд, пока ваш Droplet будет подготавливаться. Когда ваш Droplet будет готов, используйте SSH для подключения:

```console
ssh root@<droplet-ip>
```

## Настройка доменного имени

В большинстве случаев вам потребуется связать доменное имя с вашим сайтом.
Если у вас еще нет доменного имени, вам придется приобрести его через регистратора.

Затем создайте DNS-запись типа `A` для вашего доменного имени, указывающую на IP-адрес вашего сервера:

```dns
your-domain-name.example.com.  IN  A     207.154.233.113
```

Пример настройки через сервис DigitalOcean Domains ("Networking" > "Domains"):

![Настройка DNS в DigitalOcean](/blume-assets/content/content/assets/digitalocean-dns.png)

<div class="fp-callout" data-callout="note">
<p class="fp-callout-title">Примечание</p>

Let's Encrypt, сервис, используемый FrankenPHP по умолчанию для автоматической генерации TLS-сертификатов, не поддерживает использование IP-адресов напрямую. Использование доменного имени является обязательным для работы с Let's Encrypt.

</div>

## Деплой

Скопируйте ваш проект на сервер с помощью `git clone`, `scp` или любого другого подходящего инструмента.
Если вы используете GitHub, вы можете использовать [ключ развертывания](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys). Ключи развертывания также [поддерживаются GitLab](https://docs.gitlab.com/ee/user/project/deploy_keys/).

Пример с использованием Git:

```console
git clone git@github.com:<username>/<project-name>.git
```

Перейдите в директорию, содержащую ваш проект (`<project-name>`), и запустите приложение в production-режиме:

```console
docker compose up --wait
```

Ваш сервер запущен и работает, и HTTPS-сертификат был автоматически сгенерирован для вас. Перейдите на `https://your-domain-name.example.com` и наслаждайтесь!

<div class="fp-callout" data-callout="caution">
<p class="fp-callout-title">Осторожно</p>

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

</div>

## Запуск за обратным прокси

Если FrankenPHP работает за обратным прокси-сервером или балансировщиком нагрузки (например, Nginx, AWS ELB, Google Cloud LB),
вы должны настроить [глобальную опцию `trusted_proxies`](https://caddyserver.com/docs/caddyfile/options#trusted-proxies) в вашем Caddyfile,
чтобы Caddy доверял входящим заголовкам `X-Forwarded-*`:

```caddyfile
{
	servers {
		trusted_proxies static <your-IPs>
	}
}
```

Замените `<your-IPs>` на фактические диапазоны IP-адресов вашего прокси, если это необходимо.

Кроме того, ваш PHP-фреймворк также должен быть настроен на доверие прокси.
Например, установите [переменную окружения `TRUSTED_PROXIES`](https://symfony.com/doc/current/deployment/proxies.html) для Symfony
или [middleware `trustedproxies`](https://laravel.com/docs/trustedproxy) для Laravel.

Без обеих этих конфигураций заголовки, такие как `X-Forwarded-For` и `X-Forwarded-Proto`, будут игнорироваться,
что может вызвать проблемы, такие как некорректное определение HTTPS или неверные IP-адреса клиентов.

## Деплой на несколько узлов

Если вы хотите развернуть ваше приложение на кластере машин, вы можете использовать [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/),
который совместим с предоставленными Compose-файлами.
Для развертывания на Kubernetes ознакомьтесь с [Helm-чартом, поставляемым с API Platform](https://api-platform.com/docs/deployment/kubernetes/), который использует FrankenPHP.
