---
title: "Implantando em produção"
description: "Neste tutorial, aprenderemos como implantar uma aplicação PHP em um único servidor usando o Docker Compose."
sidebar:
  label: "Implantação em produção"
  order: 1
---
Se você estiver usando o Symfony, leia a documentação
"[Implantar em produção](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)"
do projeto Docker do Symfony (que usa FrankenPHP).

Se você estiver usando a API Platform (que também usa FrankenPHP), consulte
[a documentação de implantação do framework](https://api-platform.com/docs/deployment/).

## Preparando sua aplicação

Primeiro, crie um `Dockerfile` no diretório raiz do seu projeto PHP:

```dockerfile
FROM dunglas/frankenphp

# Certifique-se de substituir "your-domain-name.example.com" pelo seu nome de domínio
ENV SERVER_NAME=your-domain-name.example.com
# Se quiser desabilitar o HTTPS, use este valor:
#ENV SERVER_NAME=:80

# Se o seu projeto não estiver usando o diretório "public" como diretório raiz da web, você pode defini-lo aqui:
# ENV SERVER_ROOT=web/

# Habilita as configurações de produção do PHP
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Copia os arquivos PHP do seu projeto para o diretório public
COPY . /app/public
# Se você usa Symfony ou Laravel, precisa copiar o projeto inteiro:
#COPY . /app
```

Consulte "[Construindo uma imagem Docker personalizada](/pt-br/docs/docker)" para mais
detalhes e opções, e para aprender como personalizar a configuração, instalar
extensões PHP e módulos Caddy.

Se o seu projeto usa o Composer,
certifique-se de incluí-lo na imagem Docker e instalar suas dependências.

Em seguida, adicione um arquivo `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

# Volumes necessários para certificados e configuração do Caddy
volumes:
  caddy_data:
  caddy_config:
```

<div class="fp-callout" data-callout="note">
<p class="fp-callout-title">Nota</p>

Os exemplos anteriores são destinados ao uso em produção.
Em desenvolvimento, você pode querer usar um volume, uma configuração PHP
diferente e um valor diferente para a variável de ambiente `SERVER_NAME`.

Consulte o projeto [Symfony Docker](https://github.com/dunglas/symfony-docker)
(que usa FrankenPHP) para um exemplo mais avançado usando imagens
multiestágio, Composer, extensões PHP extras, etc.

</div>

Finalmente, se você usa Git, faça o commit e o push desses arquivos.

## Preparando um servidor

Para implantar sua aplicação em produção, você precisa de um servidor.
Neste tutorial, usaremos uma máquina virtual fornecida pela DigitalOcean, mas
qualquer servidor Linux pode ser usado.
Se você já possui um servidor Linux com o Docker instalado, pode pular direto
para [a próxima seção](#configurando-um-nome-de-domínio).

Caso contrário, use [este link de afiliado](https://m.do.co/c/5d8aabe3ab80) para
obter US$ 200 em créditos gratuitos, crie uma conta e clique em "Create a
Droplet".
Em seguida, clique na aba "Marketplace" na seção "Choose an image" e procure a
aplicação "Docker".
Isso provisionará um servidor Ubuntu com as versões mais recentes do Docker e do
Docker Compose já instaladas!

Para fins de teste, os planos mais baratos serão suficientes.
Para uso real em produção, você provavelmente escolherá um plano na seção
"General Purpose" que atenda às suas necessidades.

![Implantando o FrankenPHP na DigitalOcean com Docker](/blume-assets/content/content/assets/digitalocean-droplet.png)

Você pode manter os padrões para outras configurações ou ajustá-los de acordo
com suas necessidades.
Não se esqueça de adicionar sua chave SSH ou criar uma senha e, em seguida,
clicar no botão "Finalize and create".

Em seguida, aguarde alguns segundos enquanto seu Droplet é provisionado.
Quando seu Droplet estiver pronto, use SSH para se conectar:

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

## Configurando um nome de domínio

Na maioria dos casos, você precisará associar um nome de domínio ao seu site.
Se você ainda não possui um nome de domínio, precisará comprar um por meio de um
registrar.

Em seguida, crie um registro DNS do tipo `A` para o seu nome de domínio,
apontando para o endereço IP do seu servidor:

```dns
seu-nome-de-dominio.example.com.  IN  A     <ip-do-seu-servidor>
```

Exemplo com o serviço DigitalOcean Domains ("Networking" > "Domains"):

![Configurando DNS na DigitalOcean](/blume-assets/content/content/assets/digitalocean-dns.png)

<div class="fp-callout" data-callout="note">
<p class="fp-callout-title">Nota</p>

O Let's Encrypt, o serviço usado por padrão pelo FrankenPHP para gerar
automaticamente um certificado TLS, não suporta o uso de endereços IP.
O uso de um nome de domínio é obrigatório para usar o Let's Encrypt.

</div>

## Implantando

Copie seu projeto para o servidor usando `git clone`, `scp` ou qualquer outra
ferramenta que atenda às suas necessidades.
Se você usa o GitHub, pode ser útil usar
[uma chave de implantação](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys).
Chaves de implantação também são [suportadas pelo GitLab](https://docs.gitlab.com/ee/user/project/deploy_keys/).

Exemplo com Git:

```console
git clone git@github.com:<usuario>/<nome-do-projeto>.git
```

Acesse o diretório que contém seu projeto (`<nome-do-projeto>`) e inicie a
aplicação em modo de produção:

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

Seu servidor está funcionando e um certificado HTTPS foi gerado automaticamente
para você.
Acesse `https://seu-nome-de-dominio.example.com` e divirta-se!

<div class="fp-callout" data-callout="caution">
<p class="fp-callout-title">Cuidado</p>

O Docker pode ter uma camada de cache; certifique-se de ter a construção
correta para cada implantação ou reconstrua seu projeto com a opção
`--no-cache` para evitar problemas de cache.

</div>

## Executando por trás de um proxy reverso

Se o FrankenPHP estiver sendo executado por trás de um proxy reverso ou um balanceador de carga (por exemplo, Nginx, AWS ELB, Google Cloud LB),
você deve configurar a [opção global `trusted_proxies`](https://caddyserver.com/docs/caddyfile/options#trusted-proxies) no seu Caddyfile
para que o Caddy confie nos cabeçalhos `X-Forwarded-*` recebidos:

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

Substitua `<your-IPs>` pelos intervalos de IP reais do seu proxy, se necessário.

Além disso, seu framework PHP também deve ser configurado para confiar no proxy.
Por exemplo, defina a [variável de ambiente `TRUSTED_PROXIES`](https://symfony.com/doc/current/deployment/proxies.html) para o Symfony,
ou o [middleware `trustedproxies`](https://laravel.com/docs/trustedproxy) para o Laravel.

Sem ambas as configurações, cabeçalhos como `X-Forwarded-For` e `X-Forwarded-Proto` serão ignorados,
o que pode causar problemas como detecção incorreta de HTTPS ou endereços IP de cliente errados.

## Implantando em múltiplos nós

Se você deseja implantar sua aplicação em um cluster de máquinas, pode usar o
[Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/), que é
compatível com os arquivos Compose fornecidos.
Para implantar no Kubernetes, consulte o
[chart do Helm fornecido com a API Platform](https://api-platform.com/docs/deployment/kubernetes/),
que usa FrankenPHP.
