# Configuração

FrankenPHP, Caddy, bem como os módulos Mercure e Vulcain, podem ser configurados
usando
[os formatos suportados pelo Caddy](https://caddyserver.com/docs/getting-started#your-first-config).

Nas [imagens do Docker](docker.md), o `Caddyfile` está localizado em
`/etc/frankenphp/Caddyfile`.
O binário estático também procurará pelo `Caddyfile` no diretório onde o comando
`frankenphp run` é executado.
Você pode especificar um caminho personalizado com a opção `-c` ou `--config`.

O próprio PHP pode ser configurado
[usando um arquivo `php.ini`](https://www.php.net/manual/pt_BR/configuration.file.php).

Dependendo do seu método de instalação, o interpretador PHP procurará por
arquivos de configuração nos locais descritos acima.

## Docker

- `php.ini`: `/usr/local/etc/php/php.ini` (nenhum `php.ini` é fornecido por
  padrão)
- Arquivos de configuração adicionais: `/usr/local/etc/php/conf.d/*.ini`
- Extensões PHP: `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
- Você deve copiar um template oficial fornecido pelo projeto PHP:

```dockerfile
FROM dunglas/frankenphp

# Produção:
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini

# Ou desenvolvimento:
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
```

## Pacotes RPM e Debian

- `php.ini`: `/etc/frankenphp/php.ini` (um arquivo `php.ini` com configurações
  de produção é fornecido por padrão)
- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`
- Extensões PHP: `/usr/lib/frankenphp/modules/`

## Binário estático

- `php.ini`: O diretório no qual `frankenphp run` ou `frankenphp php-server` é
  executado e, em seguida, `/etc/frankenphp/php.ini`
- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`
- Extensões PHP: não podem ser carregadas, empacote-as no próprio binário
- Copie um dos `php.ini-production` ou `php.ini-development` fornecidos
  [nos fontes do PHP](https://github.com/php/php-src/).

## Configuração do Caddyfile

As [diretivas HTTP](https://caddyserver.com/docs/caddyfile/concepts#directives)
`php_server` ou `php` podem ser usadas dentro dos blocos de site para servir sua
aplicação PHP.

Exemplo mínimo:

```caddyfile
localhost {
    # Habilita compressão (opcional)
    encode zstd br gzip
    # Executa arquivos PHP no diretório atual e serve assets
    php_server
}
```

Você também pode configurar explicitamente o FrankenPHP usando a opção global:
A [opção global](https://caddyserver.com/docs/caddyfile/concepts#global-options)
`frankenphp` pode ser usada para configurar o FrankenPHP.

```caddyfile
{
    frankenphp {
        num_threads <num_threads> # Define o número de threads PHP a serem iniciadas. Padrão: 2x o número de CPUs disponíveis.
        max_threads <num_threads> # Limita o número de threads PHP adicionais que podem ser iniciadas em tempo de execução. Padrão: num_threads. Pode ser definido como 'auto'.
        max_wait_time <duracao> # Define o tempo máximo que uma requisição pode esperar por uma thread PHP livre antes de atingir o tempo limite. Padrão: disabled.
        php_ini <chave> <valor> # Define uma diretiva php.ini. Pode ser usada várias vezes para definir múltiplas diretivas.
        worker {
            file <caminho> # Define o caminho para o script do worker.
            num <num> # Define o número de threads PHP a serem iniciadas, o padrão é 2x o número de CPUs disponíveis.
            env <chave> <valor> # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente.
            watch <caminho> # Define o caminho para monitorar alterações no arquivo. Pode ser especificado mais de uma vez para múltiplos caminhos.
            name <nome> # Define o nome do worker, usado em logs e métricas. Padrão: caminho absoluto do arquivo do worker.
        }
    }
}

# ...
```

Alternativamente, você pode usar a forma abreviada de uma linha da opção
`worker`:

```caddyfile
{
    frankenphp {
        worker <arquivo> <num>
    }
}

# ...
```

Você também pode definir vários workers se servir várias aplicações no mesmo
servidor:

```caddyfile
app.example.com {
    php_server {
        root /caminho/para/aplicacao/public
        worker index.php <num>
    }
}

outra.example.com {
    php_server {
        root /caminho/para/outra/aplicacao/public
        worker index.php <num>
    }
}

# ...
```

Usar a diretiva `php_server` geralmente é o que você precisa, mas se precisar de
controle total, você pode usar a diretiva `php` de mais baixo nível.
A diretiva `php` passa toda a entrada para o PHP, em vez de primeiro verificar
se é um arquivo PHP ou não.
Leia mais sobre isso na [página de desempenho](performance.md#try_files).

Usar a diretiva `php_server` é equivalente a esta configuração:

```caddyfile
route {
    # Adiciona barra final para requisições de diretório
    @canonicalPath {
        file {path}/index.php
        not path */
    }
    redir @canonicalPath {path}/ 308
    # Se o arquivo requisitado não existir, tenta os arquivos index
    @indexFiles file {
        try_files {path} {path}/index.php index.php
        split_path .php
    }
    rewrite @indexFiles {http.matchers.file.relative}

    # FrankenPHP!
    @phpFiles path *.php
    php @phpFiles
    file_server
}
```

As diretivas `php_server` e `php` têm as seguintes opções:

```caddyfile
php_server [<matcher>] {
    root <directory> # Define a pasta raiz para o site. Padrão: diretiva `root`.
    split_path <delim...> # Define as substrings para dividir o URI em duas partes. A primeira substring correspondente será usada para separar as "informações de caminho" do caminho. A primeira parte é sufixada com a substring correspondente e será assumida como o nome real do recurso (script CGI). A segunda parte será definida como PATH_INFO para o script usar. Padrão: `.php`
    resolve_root_symlink false # Desabilita a resolução do diretório `root` para seu valor real avaliando um link simbólico, se houver (habilitado por padrão).
    env <chave> <valor> # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente.
    file_server off # Desabilita a diretiva interna file_server.
    worker { # Cria um worker específico para este servidor. Pode ser especificado mais de uma vez para múltiplos workers.
        file <caminho> # Define o caminho para o script do worker, pode ser relativo à raiz do php_server
        num <num> # Define o número de threads PHP a serem iniciadas, o padrão é 2x o número de threads disponíveis
        name <nome> # Define o nome do worker, usado em logs e métricas. Padrão: caminho absoluto do arquivo do worker. Sempre começa com m# quando definido em um bloco php_server.
        watch <caminho> # Define o caminho para monitorar alterações no arquivo. Pode ser especificado mais de uma vez para múltiplos caminhos.
        env <chave> <valor> # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente. As variáveis de ambiente para este worker também são herdadas do php_server pai, mas podem ser sobrescritas aqui.
    }
    worker <outro_arquivo> <num> # Também pode usar a forma abreviada, como no bloco global frankenphp.
}
```

### Monitorando alterações em arquivos

Como os workers inicializam sua aplicação apenas uma vez e a mantêm na memória,
quaisquer alterações nos seus arquivos PHP não serão refletidas imediatamente.

Os workers podem ser reiniciados em caso de alterações nos arquivos por meio da
diretiva `watch`.
Isso é útil para ambientes de desenvolvimento.

```caddyfile
{
    frankenphp {
        worker {
            file  /caminho/para/aplicacao/public/worker.php
            watch
        }
    }
}
```

Se o diretório `watch` não for especificado, ele usará o valor padrão
`./**/*.{php,yaml,yml,twig,env}`,
que monitora todos os arquivos `.php`, `.yaml`, `.yml`, `.twig` e `.env` no
diretório e subdiretórios onde o processo FrankenPHP foi iniciado.
Você também pode especificar um ou mais diretórios por meio de um
[padrão de nome de arquivo shell](https://pkg.go.dev/path/filepath#Match):

```caddyfile
{
    frankenphp {
        worker {
            file  /caminho/para/aplicacao/public/worker.php
            watch /caminho/para/aplicacao # monitora todos os arquivos em todos os subdiretórios de /caminho/para/aplicacao
            watch /caminho/para/aplicacao/*.php # monitora arquivos terminados em .php em /caminho/para/aplicacao
            watch /caminho/para/aplicacao/**/*.php # monitora arquivos PHP em /caminho/para/aplicacao e subdiretórios
            watch /caminho/para/aplicacao/**/*.{php,twig} # monitora arquivos PHP e Twig em /caminho/para/aplicacao e subdiretórios
        }
    }
}
```

- O padrão `**` significa monitoramento recursivo
- Diretórios também podem ser relativos (ao local de início do processo
  FrankenPHP)
- Se você tiver vários workers definidos, todos eles serão reiniciados quando um
  arquivo for alterado
- Tenha cuidado ao monitorar arquivos criados em tempo de execução (como logs),
  pois eles podem causar reinicializações indesejadas de workers.

O monitor de arquivos é baseado em
[e-dant/watcher](https://github.com/e-dant/watcher).

### Full Duplex (HTTP/1)

Ao usar HTTP/1.x, pode ser desejável habilitar o modo full-duplex para permitir
a gravação de uma resposta antes que todo o corpo tenha sido lido.
(por exemplo: WebSocket, Server-Sent Events, etc.)

Esta é uma configuração opcional que precisa ser adicionada às opções globais no
`Caddyfile`:

```caddyfile
{
    servers {
        enable_full_duplex
    }
}
```

> [!CAUTION]
>
> Habilitar esta opção pode causar deadlock em clientes HTTP/1.x antigos que não
> suportam full-duplex.
> Isso também pode ser configurado usando a configuração de ambiente
> `CADDY_GLOBAL_OPTIONS`:

```sh
CADDY_GLOBAL_OPTIONS="servers {
    enable_full_duplex
}"
```

Você pode encontrar mais informações sobre esta configuração na
[documentação do Caddy](https://caddyserver.com/docs/caddyfile/options#enable-full-duplex).

## Variáveis de ambiente

As seguintes variáveis de ambiente podem ser usadas para injetar diretivas Caddy
no `Caddyfile` sem modificá-lo:

- `SERVER_NAME`: altera
  [os endereços nos quais escutar](https://caddyserver.com/docs/caddyfile/concepts#addresses),
  os nomes de host fornecidos também serão usados para o certificado TLS gerado.
- `SERVER_ROOT`: altera o diretório raiz do site, o padrão é `public/`.
- `CADDY_GLOBAL_OPTIONS`: injeta
  [opções globais](https://caddyserver.com/docs/caddyfile/options).
- `FRANKENPHP_CONFIG`: injeta a configuração sob a diretiva `frankenphp`.

Quanto às SAPIs FPM e CLI, as variáveis de ambiente são expostas por padrão na
superglobal `$_SERVER`.

O valor `S` da
[diretiva `variables_order` do PHP](https://www.php.net/manual/pt_BR/ini.core.php#ini.variables-order)
é sempre equivalente a `ES`, independentemente da colocação de `E` em outra
parte desta diretiva.

## Configuração do PHP

Para carregar
[arquivos de configuração adicionais do PHP](https://www.php.net/manual/pt_BR/configuration.file.php#configuration.file.scan),
a variável de ambiente `PHP_INI_SCAN_DIR` pode ser usada.
Quando definida, o PHP carregará todos os arquivos com a extensão `.ini`
presentes nos diretórios fornecidos.

Você também pode alterar a configuração do PHP usando a diretiva `php_ini` no
`Caddyfile`:

```caddyfile
{
    frankenphp {
        php_ini memory_limit 256M

        # ou

        php_ini {
            memory_limit 256M
            max_execution_time 15
        }
    }
}
```

## Habilitar o modo de depuração

Ao usar a imagem do Docker, defina a variável de ambiente `CADDY_GLOBAL_OPTIONS`
como `debug` para habilitar o modo de depuração:

```console
docker run -v $PWD:/app/public \
    -e CADDY_GLOBAL_OPTIONS=debug \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp
```
