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.

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.jsonda sua aplicação.
A arquitetura que vamos montar
A estrutura será aproximadamente esta:
Internet
│
▼
Cloudflare / DNS
│
▼
Apache
│
▼
PHP-FPM
│
▼
Symfony
│
▼
MySQLO 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:
sudo apt update
sudo apt upgrade -yDepois, instale alguns pacotes básicos:
sudo apt install -y \
curl \
wget \
git \
unzip \
zip \
ca-certificates \
software-properties-commonEvite trabalhar permanentemente como root
Crie um usuário específico para administrar a aplicação:
sudo adduser deployAdicione o usuário ao grupo sudo:
sudo usermod -aG sudo deployA 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:
ssh-keygen -t ed25519Depois copie a chave pública para o servidor:
ssh-copy-id deploy@IP_DO_SERVIDORTeste:
ssh deploy@IP_DO_SERVIDORSomente 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:
sudo apt install -y ufwPermita SSH:
sudo ufw allow OpenSSHPermita HTTP:
sudo ufw allow 80/tcpPermita HTTPS:
sudo ufw allow 443/tcpAtive:
sudo ufw enableConfira:
sudo ufw statusEm 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:
sudo apt install -y apache2Verifique o serviço:
sudo systemctl status apache2Se necessário:
sudo systemctl enable apache2
sudo systemctl start apache2Também vamos habilitar módulos usados pelo Symfony:
sudo a2enmod rewrite
sudo a2enmod proxy_fcgi
sudo a2enmod setenvif
sudo a2enmod headers
sudo a2enmod sslRecarregue o Apache:
sudo systemctl restart apache2Neste 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:
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-bcmathVerifique a versão:
php -vVerifique o PHP-FPM:
sudo systemctl status php8.3-fpmHabilite a integração do PHP-FPM com o Apache:
sudo a2enconf php8.3-fpmDepois:
sudo systemctl restart apache2Não instale extensões sem verificar o projeto
Uma aplicação Symfony pode precisar de extensões adicionais.
Veja o composer.json:
cat composer.jsonProcure principalmente pela seção:
"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:
composer --versionUma abordagem importante é utilizar exatamente as dependências definidas pelo composer.lock.
No servidor, o comando de produção deve ser:
composer install --no-dev --prefer-dist --optimize-autoloaderEvite executar:
composer updatedurante 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:
sudo apt install -y mysql-serverVerifique:
sudo systemctl status mysqlHabilite o serviço:
sudo systemctl enable mysqlDepois execute a configuração de segurança:
sudo mysql_secure_installationAs opções apresentadas podem variar conforme a versão instalada.
7. Crie o banco de dados
Entre no MySQL:
sudo mysqlCrie o banco:
CREATE DATABASE minha_aplicacao
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Crie um usuário específico:
CREATE USER 'minha_aplicacao'@'localhost'
IDENTIFIED BY 'UMA_SENHA_FORTE';Dê acesso somente ao banco da aplicação:
GRANT ALL PRIVILEGES
ON minha_aplicacao.*
TO 'minha_aplicacao'@'localhost';Aplique as permissões:
FLUSH PRIVILEGES;Saia:
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 é:
/var/www/
└── minha-aplicacao/
├── bin/
├── config/
├── migrations/
├── public/
├── src/
├── templates/
├── var/
├── vendor/
└── composer.jsonCrie o diretório:
sudo mkdir -p /var/www/minha-aplicacaoAltere o proprietário:
sudo chown -R deploy:www-data /var/www/minha-aplicacaoO 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:
cd /var/www/minha-aplicacaoClone o projeto:
git clone https://github.com/usuario/projeto.git .Ou utilize o mecanismo de deploy adotado pela sua equipe.
Depois:
composer install \
--no-dev \
--prefer-dist \
--optimize-autoloader10. 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:
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:
git statuse 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:
var/cache/
var/log/Uma abordagem simples é:
sudo chown -R deploy:www-data /var/www/minha-aplicacaoDepois:
sudo chmod -R ug+rwX /var/www/minha-aplicacao/varO 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:
chmod -R 777 /var/www/minha-aplicacaoEsse 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:
/var/www/minha-aplicacao/publice não para:
/var/www/minha-aplicacaoCrie um VirtualHost:
sudo nano /etc/apache2/sites-available/minha-aplicacao.confExemplo:
<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:
sudo a2ensite minha-aplicacao.confDesabilite o site padrão:
sudo a2dissite 000-default.confTeste a configuração:
sudo apachectl configtestO resultado esperado:
Syntax OKRecarregue:
sudo systemctl reload apache213. Por que o DocumentRoot deve apontar para public/?
Essa é uma das configurações mais importantes em uma aplicação Symfony.
O diretório:
public/é a fronteira pública da aplicação.
Arquivos como:
.env
composer.json
composer.lock
config/
src/
var/não devem ser diretamente acessíveis pelo navegador.
Um request como:
https://exemplo.com/deve chegar ao front controller:
public/index.phpe 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:
A
exemplo.com
203.0.113.10E, se necessário:
A
www.exemplo.com
203.0.113.10Antes de continuar, valide:
dig exemplo.comou:
nslookup exemplo.comO 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:
sudo apt install -y certbot python3-certbot-apacheExecute:
sudo certbot --apache -d exemplo.com -d www.exemplo.comDepois teste a configuração:
sudo apachectl configtestO Certbot também pode configurar o redirecionamento de HTTP para HTTPS.
Confira a renovação:
sudo systemctl status certbot.timer16. Execute as tarefas do Symfony
Com o código instalado e as variáveis configuradas:
cd /var/www/minha-aplicacaoLimpe e aqueça o cache:
APP_ENV=prod php bin/console cache:clearExecute as migrações, quando aplicável:
php bin/console doctrine:migrations:migrate --no-interactionConfira o ambiente:
php bin/console aboutA ideia é que a aplicação esteja sendo executada explicitamente em produção:
APP_ENV=prod
APP_DEBUG=017. Teste pelo próprio servidor
Antes de culpar o Apache, teste cada camada separadamente.
Confira o PHP:
php -vConfira o FPM:
sudo systemctl status php8.3-fpmConfira o MySQL:
sudo systemctl status mysqlConfira o Apache:
sudo systemctl status apache2Confira as portas:
sudo ss -lntpConfira o VirtualHost:
sudo apachectl -SConfira os logs:
sudo tail -f /var/log/apache2/minha-aplicacao-error.loge:
sudo tail -f /var/log/apache2/minha-aplicacao-access.logTambém vale verificar:
tail -f var/log/prod.logquando 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:
[ ] 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 configurado19. 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:
mysqldump \
-u minha_aplicacao \
-p \
minha_aplicacao \
> backup.sqlMas 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:
VPS
│
├── Banco de produção
│
└── Backup local
│
▼
armazenamento externoTambé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:
git pull
composer install --no-dev --prefer-dist --optimize-autoloader
php bin/console doctrine:migrations:migrate --no-interaction
php bin/console cache:clearEm projetos pequenos isso pode ser suficiente.
À medida que a aplicação cresce, podemos evoluir para:
Git
│
▼
CI/CD
│
▼
Build
│
▼
Deploy
│
├── composer install
├── migrations
├── cache
└── restart workersPara 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:
Segurança
↓
Sistema operacional
↓
Runtime da aplicação
↓
Deploy e operaçãoO 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.