Pular para o conteúdo
Fernando Valler

Como preparar uma VPS do zero para uma aplicação Symfony com Apache, PHP-FPM e MySQL

Um guia prático para configurar uma VPS Ubuntu para hospedar uma aplicação Symfony em produção usando Apache, PHP-FPM, MySQL, Composer e HTTPS.

Como preparar uma VPS do zero para uma aplicação Symfony com Apache, PHP-FPM e MySQL

Subir uma aplicação Symfony para uma VPS não começa com o git clone.

Antes de publicar o código, é necessário preparar o servidor: atualizar o sistema operacional, configurar acesso seguro, instalar o Apache, PHP-FPM e extensões necessárias, preparar o MySQL, configurar o domínio, ajustar permissões e habilitar HTTPS.

Neste artigo, vamos partir de uma VPS Ubuntu praticamente vazia e chegar a um ambiente capaz de executar uma aplicação Symfony em produção.

O objetivo não é criar uma infraestrutura extremamente sofisticada, mas estabelecer uma base segura, previsível e fácil de manter.

Os comandos deste artigo usam Ubuntu 24.04 como referência. Ajuste a versão do PHP, extensões e caminhos conforme o composer.json da sua aplicação.

A arquitetura que vamos montar

A estrutura será aproximadamente esta:

text
Internet
   │
   ▼
Cloudflare / DNS
   │
   ▼
Apache
   │
   ▼
PHP-FPM
   │
   ▼
Symfony
   │
   ▼
MySQL

O Apache será responsável por receber as requisições HTTP/HTTPS e servir os arquivos públicos da aplicação.

O PHP-FPM executará o PHP.

O Symfony ficará fora da raiz pública do servidor, com apenas o diretório public/ exposto pelo Apache.

O MySQL ficará acessível localmente pelo servidor, sem necessidade de expor a porta 3306 para a Internet.


1. Comece pela segurança da VPS

Uma VPS nova deve ser preparada antes de receber a aplicação.

Primeiro, atualize os pacotes:

bash
sudo apt update
sudo apt upgrade -y

Depois, instale alguns pacotes básicos:

bash
sudo apt install -y \
    curl \
    wget \
    git \
    unzip \
    zip \
    ca-certificates \
    software-properties-common

Evite trabalhar permanentemente como root

Crie um usuário específico para administrar a aplicação:

bash
sudo adduser deploy

Adicione o usuário ao grupo sudo:

bash
sudo usermod -aG sudo deploy

A partir desse ponto, prefira utilizar o usuário deploy para operações relacionadas à aplicação.

Configure autenticação SSH por chave

No computador local, gere uma chave caso ainda não possua uma:

bash
ssh-keygen -t ed25519

Depois copie a chave pública para o servidor:

bash
ssh-copy-id deploy@IP_DO_SERVIDOR

Teste:

bash
ssh deploy@IP_DO_SERVIDOR

Somente depois de validar o acesso por chave vale considerar desabilitar o login SSH por senha.

Também é importante evitar expor serviços desnecessários na Internet.


2. Configure o firewall

No Ubuntu, o ufw pode fornecer uma camada simples de filtragem de portas.

Instale:

bash
sudo apt install -y ufw

Permita SSH:

bash
sudo ufw allow OpenSSH

Permita HTTP:

bash
sudo ufw allow 80/tcp

Permita HTTPS:

bash
sudo ufw allow 443/tcp

Ative:

bash
sudo ufw enable

Confira:

bash
sudo ufw status

Em uma aplicação tradicional com Apache e MySQL local, não existe motivo para abrir a porta 3306 para a Internet.


3. Instale o Apache

Instale o servidor web:

bash
sudo apt install -y apache2

Verifique o serviço:

bash
sudo systemctl status apache2

Se necessário:

bash
sudo systemctl enable apache2
sudo systemctl start apache2

Também vamos habilitar módulos usados pelo Symfony:

bash
sudo a2enmod rewrite
sudo a2enmod proxy_fcgi
sudo a2enmod setenvif
sudo a2enmod headers
sudo a2enmod ssl

Recarregue o Apache:

bash
sudo systemctl restart apache2

Neste ponto, acessar o IP do servidor pelo navegador já deve exibir a página padrão do Apache.


4. Instale PHP e PHP-FPM

O Symfony não depende apenas do pacote php.

Precisamos do PHP-FPM e das extensões utilizadas pela aplicação.

Um exemplo para PHP 8.3:

bash
sudo apt install -y \
    php8.3 \
    php8.3-fpm \
    php8.3-cli \
    php8.3-common \
    php8.3-mysql \
    php8.3-intl \
    php8.3-mbstring \
    php8.3-xml \
    php8.3-curl \
    php8.3-zip \
    php8.3-opcache \
    php8.3-bcmath

Verifique a versão:

bash
php -v

Verifique o PHP-FPM:

bash
sudo systemctl status php8.3-fpm

Habilite a integração do PHP-FPM com o Apache:

bash
sudo a2enconf php8.3-fpm

Depois:

bash
sudo systemctl restart apache2

Não instale extensões sem verificar o projeto

Uma aplicação Symfony pode precisar de extensões adicionais.

Veja o composer.json:

bash
cat composer.json

Procure principalmente pela seção:

json
"require": {
    "php": "...",
    "ext-intl": "*",
    "ext-pdo": "*",
    "ext-xml": "*"
}

O servidor deve atender às mesmas exigências do projeto.


5. Instale o Composer

O Composer será utilizado para instalar as dependências da aplicação.

Depois de instalar, confirme:

bash
composer --version

Uma abordagem importante é utilizar exatamente as dependências definidas pelo composer.lock.

No servidor, o comando de produção deve ser:

bash
composer install --no-dev --prefer-dist --optimize-autoloader

Evite executar:

bash
composer update

durante um deploy normal.

composer update pode alterar as versões instaladas das dependências. Em produção, o objetivo normalmente é reproduzir o conjunto de versões já definido pelo projeto.


6. Instale o MySQL

Instale:

bash
sudo apt install -y mysql-server

Verifique:

bash
sudo systemctl status mysql

Habilite o serviço:

bash
sudo systemctl enable mysql

Depois execute a configuração de segurança:

bash
sudo mysql_secure_installation

As opções apresentadas podem variar conforme a versão instalada.


7. Crie o banco de dados

Entre no MySQL:

bash
sudo mysql

Crie o banco:

sql
CREATE DATABASE minha_aplicacao
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

Crie um usuário específico:

sql
CREATE USER 'minha_aplicacao'@'localhost'
IDENTIFIED BY 'UMA_SENHA_FORTE';

Dê acesso somente ao banco da aplicação:

sql
GRANT ALL PRIVILEGES
ON minha_aplicacao.*
TO 'minha_aplicacao'@'localhost';

Aplique as permissões:

sql
FLUSH PRIVILEGES;

Saia:

sql
EXIT;

A aplicação não precisa utilizar o usuário root.

Essa separação é importante porque um comprometimento da aplicação não deveria conceder automaticamente controle administrativo sobre todos os bancos do servidor.


8. Crie a estrutura da aplicação

Um caminho simples é:

text
/var/www/
└── minha-aplicacao/
    ├── bin/
    ├── config/
    ├── migrations/
    ├── public/
    ├── src/
    ├── templates/
    ├── var/
    ├── vendor/
    └── composer.json

Crie o diretório:

bash
sudo mkdir -p /var/www/minha-aplicacao

Altere o proprietário:

bash
sudo chown -R deploy:www-data /var/www/minha-aplicacao

O objetivo é permitir que o usuário de deploy gerencie o código enquanto o PHP-FPM, executando como www-data, tenha acesso somente ao que precisa.


9. Faça o deploy do código

Entre no diretório:

bash
cd /var/www/minha-aplicacao

Clone o projeto:

bash
git clone https://github.com/usuario/projeto.git .

Ou utilize o mecanismo de deploy adotado pela sua equipe.

Depois:

bash
composer install \
    --no-dev \
    --prefer-dist \
    --optimize-autoloader

10. Configure as variáveis de ambiente

Uma aplicação Symfony não deve depender de credenciais armazenadas diretamente no código-fonte.

Para produção, você pode trabalhar com variáveis de ambiente ou um arquivo local fora do controle do Git.

Por exemplo:

bash
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=uma-chave-secreta
DATABASE_URL="mysql://minha_aplicacao:[email protected]:3306/minha_aplicacao?serverVersion=8.0"

O arquivo utilizado deve estar protegido e não deve ser versionado.

Antes do deploy, confira:

bash
git status

e certifique-se de que arquivos contendo segredos não estão sendo enviados para o repositório.


11. Configure as permissões do Symfony

O Symfony precisa escrever principalmente dentro de:

text
var/cache/
var/log/

Uma abordagem simples é:

bash
sudo chown -R deploy:www-data /var/www/minha-aplicacao

Depois:

bash
sudo chmod -R ug+rwX /var/www/minha-aplicacao/var

O importante é conceder ao processo do PHP apenas as permissões necessárias.

Não é uma boa prática transformar toda a aplicação em algo como:

bash
chmod -R 777 /var/www/minha-aplicacao

Esse tipo de comando costuma esconder problemas de permissões e amplia desnecessariamente a superfície de ataque.


12. Configure o Apache

O ponto mais importante da configuração é que o Apache deve apontar para:

text
/var/www/minha-aplicacao/public

e não para:

text
/var/www/minha-aplicacao

Crie um VirtualHost:

bash
sudo nano /etc/apache2/sites-available/minha-aplicacao.conf

Exemplo:

apache
<VirtualHost *:80>
    ServerName exemplo.com
    ServerAlias www.exemplo.com

    DocumentRoot /var/www/minha-aplicacao/public

    <Directory /var/www/minha-aplicacao/public>
        AllowOverride All
        Require all granted
        Options FollowSymLinks
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/minha-aplicacao-error.log
    CustomLog ${APACHE_LOG_DIR}/minha-aplicacao-access.log combined
</VirtualHost>

Habilite o site:

bash
sudo a2ensite minha-aplicacao.conf

Desabilite o site padrão:

bash
sudo a2dissite 000-default.conf

Teste a configuração:

bash
sudo apachectl configtest

O resultado esperado:

text
Syntax OK

Recarregue:

bash
sudo systemctl reload apache2

13. Por que o DocumentRoot deve apontar para public/?

Essa é uma das configurações mais importantes em uma aplicação Symfony.

O diretório:

text
public/

é a fronteira pública da aplicação.

Arquivos como:

text
.env
composer.json
composer.lock
config/
src/
var/

não devem ser diretamente acessíveis pelo navegador.

Um request como:

text
https://exemplo.com/

deve chegar ao front controller:

text
public/index.php

e o Symfony assume o restante do processamento.

Essa separação também reduz a possibilidade de exposição acidental de arquivos internos do projeto.


14. Configure o DNS

No provedor de DNS, aponte o domínio para o IP público da VPS.

Por exemplo:

text
A
exemplo.com
203.0.113.10

E, se necessário:

text
A
www.exemplo.com
203.0.113.10

Antes de continuar, valide:

bash
dig exemplo.com

ou:

bash
nslookup exemplo.com

O DNS deve resolver para o endereço correto do servidor.


15. Habilite HTTPS

Para uma aplicação pública, HTTPS não deve ser tratado como um detalhe opcional.

Uma alternativa comum é utilizar Let’s Encrypt com Certbot.

Instale:

bash
sudo apt install -y certbot python3-certbot-apache

Execute:

bash
sudo certbot --apache -d exemplo.com -d www.exemplo.com

Depois teste a configuração:

bash
sudo apachectl configtest

O Certbot também pode configurar o redirecionamento de HTTP para HTTPS.

Confira a renovação:

bash
sudo systemctl status certbot.timer

16. Execute as tarefas do Symfony

Com o código instalado e as variáveis configuradas:

bash
cd /var/www/minha-aplicacao

Limpe e aqueça o cache:

bash
APP_ENV=prod php bin/console cache:clear

Execute as migrações, quando aplicável:

bash
php bin/console doctrine:migrations:migrate --no-interaction

Confira o ambiente:

bash
php bin/console about

A ideia é que a aplicação esteja sendo executada explicitamente em produção:

text
APP_ENV=prod
APP_DEBUG=0

17. Teste pelo próprio servidor

Antes de culpar o Apache, teste cada camada separadamente.

Confira o PHP:

bash
php -v

Confira o FPM:

bash
sudo systemctl status php8.3-fpm

Confira o MySQL:

bash
sudo systemctl status mysql

Confira o Apache:

bash
sudo systemctl status apache2

Confira as portas:

bash
sudo ss -lntp

Confira o VirtualHost:

bash
sudo apachectl -S

Confira os logs:

bash
sudo tail -f /var/log/apache2/minha-aplicacao-error.log

e:

bash
sudo tail -f /var/log/apache2/minha-aplicacao-access.log

Também vale verificar:

bash
tail -f var/log/prod.log

quando a aplicação estiver utilizando o logger padrão nesse ambiente.


18. O checklist de uma VPS Symfony

Antes de considerar a instalação concluída, eu verificaria:

text
[ ] Sistema operacional atualizado
[ ] Usuário deploy criado
[ ] SSH por chave funcionando
[ ] Login root por SSH revisado
[ ] Firewall configurado
[ ] Apenas portas necessárias expostas
[ ] Apache instalado
[ ] PHP instalado
[ ] PHP-FPM funcionando
[ ] Extensões PHP necessárias instaladas
[ ] Composer instalado
[ ] MySQL instalado
[ ] Banco criado
[ ] Usuário específico do banco criado
[ ] Porta 3306 não exposta publicamente
[ ] Código instalado
[ ] composer.lock utilizado no deploy
[ ] Variáveis de ambiente configuradas
[ ] Diretório public/ como DocumentRoot
[ ] Permissões do var/ ajustadas
[ ] VirtualHost configurado
[ ] DNS apontando para a VPS
[ ] HTTPS configurado
[ ] APP_ENV=prod
[ ] APP_DEBUG=0
[ ] Migrações executadas
[ ] Cache de produção aquecido
[ ] Logs funcionando
[ ] Backup do banco configurado

19. Backup não é opcional

Uma aplicação funcionando não significa que os dados estão protegidos.

O mínimo esperado para uma aplicação com dados importantes é ter uma rotina automatizada de backup do MySQL.

Por exemplo:

bash
mysqldump \
    -u minha_aplicacao \
    -p \
    minha_aplicacao \
    > backup.sql

Mas não pare no arquivo local.

Um backup armazenado somente na mesma VPS pode ser perdido junto com o servidor.

Uma estratégia mais adequada normalmente envolve:

text
VPS
 │
 ├── Banco de produção
 │
 └── Backup local
       │
       ▼
   armazenamento externo

Também é importante testar periodicamente a restauração.

Um backup que nunca foi restaurado é apenas uma hipótese de backup.


20. E o deploy das próximas versões?

Depois que a VPS está funcionando, não deveríamos repetir manualmente todos os passos.

Um fluxo simples pode ser:

bash
git pull
composer install --no-dev --prefer-dist --optimize-autoloader
php bin/console doctrine:migrations:migrate --no-interaction
php bin/console cache:clear

Em projetos pequenos isso pode ser suficiente.

À medida que a aplicação cresce, podemos evoluir para:

text
Git
 │
 ▼
CI/CD
 │
 ▼
Build
 │
 ▼
Deploy
 │
 ├── composer install
 ├── migrations
 ├── cache
 └── restart workers

Para aplicações críticas, também vale considerar releases versionadas, rollback, ambiente de staging e deploys que não interrompam o tráfego.

A documentação oficial do Symfony recomenda considerar testes, migrações, cache, versionamento e estratégias de rollback como parte do processo de deployment.


Conclusão

Preparar uma VPS para Symfony não significa apenas instalar Apache, PHP e MySQL.

Uma infraestrutura funcional precisa considerar pelo menos quatro camadas:

text
Segurança
    ↓
Sistema operacional
    ↓
Runtime da aplicação
    ↓
Deploy e operação

O Apache precisa saber exatamente o que pode ser público.

O PHP-FPM precisa executar a aplicação com as extensões corretas.

O MySQL precisa estar protegido e acessível somente por quem realmente necessita.

E o processo de deploy precisa ser reproduzível.

Quando essa base está bem configurada, publicar uma nova versão do Symfony deixa de ser uma sequência de comandos feitos manualmente no servidor e passa a ser um processo previsível.

Referências oficiais