Como instalar e configurar um servidor web Linux com Apache, PHP e MySQL

Introdução

Um servidor web Linux reúne serviços responsáveis por receber requisições, executar aplicações, armazenar informações e permitir a administração do sistema. Neste tutorial, vamos preparar esse ambiente em distribuições que utilizam o APT, com foco em Ubuntu e Debian.

Os procedimentos podem ser utilizados tanto no Ubuntu Desktop quanto no Ubuntu Server. A presença de uma interface gráfica não muda os comandos de instalação dos serviços. O que pode variar entre distribuições e versões são as versões dos pacotes, os nomes de alguns serviços e a implementação do banco de dados disponibilizada pelos repositórios.

Vamos instalar Apache2, SSH, um servidor de banco de dados (MySQL ou MariaDB), PHP e PHP-FPM. Também veremos como organizar os arquivos dos sites, configurar Virtual Hosts e verificar os serviços.

  1. Apache2: servidor web que recebe requisições HTTP e entrega arquivos.
  2. SSH: serviço que permite acessar o terminal por uma conexão segura.
  3. MySQL ou MariaDB: sistema gerenciador de banco de dados relacional.
  4. PHP: linguagem utilizada para executar aplicações no servidor.
  5. PHP-FPM: gerenciador de processos que executa PHP por meio do protocolo FastCGI; o Apache precisa ser configurado para encaminhar as requisições a ele.

O objetivo é preparar a infraestrutura para hospedar aplicações PHP. Não vamos desenvolver uma aplicação, criar um banco específico para um projeto ou configurar as credenciais de conexão de uma aplicação.

Compatibilidade e diferenças entre distribuições

Os comandos deste tutorial foram organizados para Ubuntu e Debian e podem ser aplicados em instalações Desktop ou Server. Eles pressupõem uma instalação baseada em APT e systemd, que são os padrões nas versões atuais dessas distribuições.

Não fixamos uma versão específica do Debian ou do Ubuntu. O APT instala a versão dos pacotes disponibilizada pelos repositórios configurados no sistema. Por isso, a versão do PHP pode mudar conforme a distribuição, a versão do sistema e os repositórios habilitados.

Há uma diferença importante no banco de dados: nos repositórios oficiais do Ubuntu, o pacote mysql-server disponibiliza o MySQL; no Debian, a opção padrão dos repositórios é normalmente o MariaDB, instalado pelo pacote mariadb-server. MariaDB é compatível com grande parte do ecossistema MySQL, mas não é o mesmo produto. Se uma aplicação exigir especificamente Oracle MySQL, confira os requisitos e siga a documentação oficial do MySQL para a distribuição utilizada.

ComponenteUbuntuDebian
Gerenciador de pacotesAPTAPT
Apacheapache2apache2
SSHopenssh-serveropenssh-server
Banco de dados deste tutorialMySQL ServerMariaDB Server
PHPVersão disponível nos repositórios configuradosVersão disponível nos repositórios configurados

Os nomes de pacotes apresentados são os dos repositórios oficiais. Repositórios externos, versões antigas, instalações mínimas ou configurações personalizadas podem alterar a disponibilidade e as versões dos pacotes.

Como os componentes trabalham juntos

ComponenteResponsabilidade
Apache2Receber requisições HTTP e entregar arquivos.
SSHPermitir administração segura do terminal.
MySQL ou MariaDBArmazenar e organizar informações.
PHP CLIExecutar scripts PHP pelo terminal.
PHP-FPMExecutar scripts PHP solicitados pelo servidor web.

O fluxo básico de uma requisição PHP é:

  1. O visitante acessa o endereço do site pelo navegador.
  2. O Apache recebe a requisição.
  3. Se for um arquivo estático, como HTML, CSS ou imagem, o Apache entrega o arquivo.
  4. Se for um arquivo PHP, o Apache encaminha a solicitação ao PHP-FPM por FastCGI.
  5. O PHP-FPM executa o código e devolve o resultado ao Apache.
  6. O Apache envia a resposta ao navegador.

O MySQL ou MariaDB funciona separadamente e pode armazenar informações utilizadas pelas aplicações. A comunicação entre PHP e o banco depende das configurações e credenciais da aplicação.

Preparando o Ubuntu ou Debian

Confira a distribuição e a versão instaladas:

cat /etc/os-release

Atualize a lista de pacotes:

sudo apt update

Instale as atualizações disponíveis:

sudo apt upgrade -y

Se o sistema solicitar uma reinicialização, faça isso em um momento adequado:

sudo reboot

Após o computador reiniciar, entre novamente e continue. Em máquinas de produção, planeje atualizações e reinicializações para evitar indisponibilidade inesperada.

Instalando e utilizando o SSH

O SSH permite acessar o terminal por uma conexão segura. O pacote utilizado tanto no Ubuntu quanto no Debian é openssh-server, e o serviço normalmente se chama ssh.

Instalação

sudo apt install openssh-server -y
sudo systemctl enable --now ssh

Verifique o serviço:

sudo systemctl status ssh

O estado esperado é active (running).

Testando uma conexão local

Descubra o nome do usuário atual:

whoami

Conecte-se ao próprio computador:

ssh "$(whoami)"@localhost

Na primeira conexão, pode aparecer uma mensagem para confirmar a identidade do servidor. Como o destino deste teste é localhost, confirme a conexão e informe a senha do usuário Linux, se solicitada. Para encerrar:

exit

Importante: localhost representa o próprio computador. Esse teste não configura acesso remoto pela rede e não exige liberar a porta 22 no firewall. Se você administra o computador remotamente, não ative um firewall sem antes criar uma regra que preserve seu acesso SSH.

Instalando o Apache2

Ubuntu e Debian utilizam o pacote apache2, o serviço apache2 e ferramentas como a2ensite, a2dissite e a2enmod.

Instalação

sudo apt install apache2 -y
sudo systemctl enable --now apache2

Verifique o serviço e a versão:

sudo systemctl status apache2
apache2 -v

Valide a configuração:

sudo apache2ctl configtest

O resultado esperado é Syntax OK.

Testando o Apache pelo navegador

Descubra os endereços IP da máquina:

hostname -I

Em um navegador que consiga alcançar o computador, acesse http://IP_DO_SERVIDOR/, substituindo o texto pelo IP correto. Se a instalação estiver funcionando e a rede permitir o acesso, será exibida a página padrão do Apache.

Onde o Apache lê os arquivos dos sites?

Nas instalações padrão dos pacotes Ubuntu e Debian, o diretório inicial utilizado pelo Apache costuma ser:

/var/www/html/

Esse diretório é o DocumentRoot, ou seja, a raiz pública de arquivos de um Virtual Host. A configuração padrão normalmente fica em:

/etc/apache2/sites-available/000-default.conf

Dentro do arquivo, procure uma diretiva semelhante a:

DocumentRoot /var/www/html

Isso significa que o Apache procura os arquivos solicitados dentro desse diretório.

Entendendo a relação entre endereço e arquivo

/var/www/html/
├── index.html
├── contato.html
├── info.php
├── css/
│   └── estilo.css
├── js/
│   └── script.js
└── imagens/
    └── logo.png
Endereço acessadoArquivo procurado
http://IP//var/www/html/index.html ou outro índice configurado
http://IP/contato.html/var/www/html/contato.html
http://IP/info.php/var/www/html/info.php
http://IP/css/estilo.css/var/www/html/css/estilo.css
http://IP/imagens/logo.png/var/www/html/imagens/logo.png

A diretiva DirectoryIndex define os nomes de arquivos procurados como página inicial, como index.html e index.php.

Criando uma página HTML

sudo nano /var/www/html/index.html

Adicione:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Meu servidor Apache</title>
</head>
<body>
    <h1>Apache funcionando!</h1>
    <p>Esta página está sendo servida pelo Linux.</p>
</body>
</html>

Salve o arquivo e acesse http://IP_DO_SERVIDOR/. A página criada deverá aparecer no navegador.

Criando diretórios para projetos

Não é necessário colocar todos os projetos dentro de /var/www/html. Você pode organizar os arquivos em diretórios separados:

/var/www/
├── html/
│   └── index.html
├── projeto1/
│   ├── index.php
│   ├── css/
│   └── imagens/
└── projeto2/
    ├── index.php
    ├── css/
    └── imagens/

Criar uma pasta não significa que ela estará automaticamente disponível pelo navegador. Para publicar outro diretório como um site independente, configure um Virtual Host.

Configurando Virtual Hosts

Virtual Hosts permitem hospedar vários sites no mesmo servidor, cada um com seu domínio e diretório de arquivos.

Domínio de exemploDiretório
site1.exemplo.com/var/www/site1
site2.exemplo.com/var/www/site2
site3.exemplo.com/var/www/site3

Criando o diretório do projeto

sudo mkdir -p /var/www/meusite
sudo nano /var/www/meusite/index.php

Adicione ao arquivo:

<?php
echo "Meu site está funcionando com Apache e PHP!";

Ajustando as permissões

Nas instalações padrão de Ubuntu e Debian, o Apache utiliza normalmente o usuário e grupo www-data. Os arquivos publicados precisam permitir leitura pelo serviço. Uma configuração inicial é:

sudo chown -R root:www-data /var/www/meusite
sudo find /var/www/meusite -type d -exec chmod 755 {} \;
sudo find /var/www/meusite -type f -exec chmod 644 {} \;

O proprietário administrativo controla os arquivos, enquanto o grupo do Apache consegue lê-los. Se uma aplicação precisar gravar uploads, cache ou sessões, conceda escrita somente aos diretórios específicos e considerando o usuário efetivo do PHP-FPM. Não utilize chmod -R 777.

Criando a configuração do Virtual Host

Os arquivos de configuração ficam em:

/etc/apache2/sites-available/

Crie o arquivo:

sudo nano /etc/apache2/sites-available/meusite.conf

Adicione:

<VirtualHost *:80>
    ServerName meusite.local
    DocumentRoot /var/www/meusite

    <Directory /var/www/meusite>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    DirectoryIndex index.php index.html

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

Principais diretivas:

  1. VirtualHost *:80: atende requisições HTTP na porta 80.
  2. ServerName: informa o domínio utilizado para identificar o site.
  3. DocumentRoot: informa onde estão os arquivos publicados.
  4. Directory: define regras de acesso ao diretório.
  5. Options -Indexes: impede a listagem automática dos arquivos.
  6. AllowOverride None: impede que arquivos .htaccess substituam as configurações desse diretório.
  7. Require all granted: permite que o Apache entregue o conteúdo.
  8. DirectoryIndex: define os nomes dos arquivos procurados como página inicial.
  9. ErrorLog e CustomLog: definem os arquivos de registro de erros e acessos.

Utilizamos AllowOverride None porque este exemplo não depende de .htaccess. Se uma aplicação precisar desse recurso, habilite somente as categorias de diretivas necessárias.

Ativando o Virtual Host

sudo a2ensite meusite.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

Se aparecer Syntax OK, a configuração foi aceita. Desative o site padrão somente se não precisar mais dele:

sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

O diretório /etc/apache2/sites-enabled/ contém os links simbólicos das configurações habilitadas. Utilize a2ensite e a2dissite para gerenciar os sites.

Testando o domínio local

Para testar meusite.local, adicione uma entrada no arquivo /etc/hosts do computador cliente:

192.168.1.100 meusite.local

Substitua o IP pelo endereço real do servidor. Acesse http://meusite.local/. Para publicar um domínio na internet, configure o DNS para apontar para o endereço público correto e ajuste a rede e o firewall.

Conhecendo os principais diretórios do Apache2

CaminhoFinalidade
/var/www/html/Diretório padrão do site inicial.
/var/www/Local comum para armazenar projetos.
/etc/apache2/Configurações principais.
/etc/apache2/apache2.confConfiguração geral.
/etc/apache2/ports.confPortas utilizadas.
/etc/apache2/sites-available/Configurações disponíveis dos sites.
/etc/apache2/sites-enabled/Configurações habilitadas.
/etc/apache2/mods-available/Módulos disponíveis.
/etc/apache2/mods-enabled/Módulos habilitados.
/var/log/apache2/Registros de acesso e erros.

Esses são os caminhos padrão dos pacotes Ubuntu e Debian. Instalações personalizadas podem utilizar outros diretórios.

Para consultar os sites habilitados:

ls -l /etc/apache2/sites-enabled/

Para consultar os Virtual Hosts reconhecidos:

sudo apache2ctl -S

Para identificar o MPM utilizado:

sudo apache2ctl -M | grep mpm

O Apache pode utilizar diferentes módulos de processamento de requisições, chamados MPMs, como event, worker e prefork. Com PHP-FPM, é possível trabalhar com o MPM Event, pois o PHP é executado em processos separados do Apache.

Instalando o servidor de banco de dados

O nome do pacote e o produto disponibilizado como padrão podem variar entre as distribuições. No Ubuntu, este tutorial utiliza o pacote mysql-server. No Debian, utiliza mariadb-server, que instala o MariaDB, uma implementação compatível com grande parte do ecossistema MySQL, mas que não é o mesmo produto.

Ubuntu: instalando MySQL Server

sudo apt install mysql-server -y
sudo systemctl enable --now mysql

Verifique o serviço e a versão:

sudo systemctl status mysql
mysql --version

Em instalações padrão, a administração local pode utilizar autenticação por socket:

sudo mysql

Se aparecer o prompt mysql>, o acesso administrativo local funcionou. Para sair:

exit;

Debian: instalando MariaDB Server

sudo apt install mariadb-server -y
sudo systemctl enable --now mariadb

Verifique o serviço e a versão:

sudo systemctl status mariadb
mariadb --version

Acesse o cliente administrativo local:

sudo mariadb

Para sair:

exit;

O cliente MariaDB também pode oferecer o comando mysql por compatibilidade, mas usar mariadb deixa explícito qual cliente está sendo executado.

Se uma aplicação exigir especificamente Oracle MySQL, não substitua automaticamente por MariaDB. Consulte os requisitos da aplicação e a documentação oficial do MySQL para instalar o produto adequado à distribuição.

Não vamos liberar o banco para conexões externas. Em um servidor onde a aplicação e o banco funcionam na mesma máquina, mantenha o acesso local, salvo necessidade arquitetural devidamente protegida.

Confira as portas em uso:

sudo ss -lntp | grep -E '3306|mysql|mariadb' || true

A saída depende da configuração do serviço. Verifique se o banco está escutando somente em interface local quando não houver necessidade de conexões remotas.

Instalando PHP e PHP-FPM

Para evitar fixar uma versão que pode não existir nos repositórios de outra versão do sistema, utilizaremos os nomes genéricos dos pacotes. O APT selecionará a versão padrão disponível nos repositórios configurados.

Instalando os pacotes

sudo apt install \
  php \
  php-cli \
  php-fpm \
  php-common \
  php-curl \
  php-mbstring \
  php-xml \
  php-zip \
  php-gd \
  php-mysql \
  -y
PacoteFinalidade
phpMetapacote da versão padrão do PHP.
php-cliExecuta scripts pelo terminal.
php-fpmGerencia os processos PHP para o servidor web.
php-commonComponentes comuns.
php-curlComunicação HTTP e integração com APIs.
php-mbstringManipulação de textos multibyte.
php-xmlProcessamento de XML.
php-zipManipulação de arquivos ZIP.
php-gdProcessamento de imagens.
php-mysqlExtensões PDO MySQL e MySQLi para conexão com MySQL/MariaDB.

O pacote php-mysql disponibiliza extensões de conexão. Ele não cria bancos, usuários ou credenciais automaticamente.

Entendendo PHP CLI e PHP-FPM

O PHP CLI executa scripts diretamente no terminal:

php -v

O PHP-FPM mantém processos que recebem solicitações FastCGI do servidor web. Consulte a versão e os serviços instalados:

php -v
php -m
systemctl list-units --type=service 'php*-fpm.service'

Descubra a versão principal e secundária do PHP:

php -r 'echo PHP_MAJOR_VERSION, ".", PHP_MINOR_VERSION, PHP_EOL;'

O serviço FPM normalmente segue o padrão phpX.Y-fpm, em que X.Y representa a versão instalada. O pacote genérico php-fpm acompanha a versão padrão dos repositórios, mas sistemas com múltiplas versões ou repositórios externos podem ter mais de um serviço instalado. Confira sempre se o serviço, o arquivo de configuração do Apache e o socket pertencem à mesma versão.

Integrando o PHP-FPM ao Apache2

Instalar o PHP-FPM não significa que o Apache já esteja utilizando o serviço. É necessário habilitar os módulos FastCGI e a configuração correspondente à versão instalada do PHP.

Descubra a versão:

PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION, ".", PHP_MINOR_VERSION;')"
echo "$PHP_VERSION"

Ative os módulos necessários:

sudo a2enmod proxy_fcgi setenvif

Ative a configuração FPM correspondente. O exemplo usa a variável descoberta anteriormente:

sudo a2enconf "php${PHP_VERSION}-fpm"

Valide a configuração e reinicie os serviços:

sudo apache2ctl configtest
sudo systemctl restart "php${PHP_VERSION}-fpm"
sudo systemctl restart apache2

Verifique o módulo e os sockets disponíveis:

sudo apache2ctl -M | grep proxy_fcgi
ls -l /run/php/

O socket normalmente segue o padrão /run/php/phpX.Y-fpm.sock. O número precisa corresponder à versão instalada. Se o arquivo de configuração esperado não existir, confira os pacotes e arquivos disponíveis em /etc/apache2/conf-available/ e /etc/php/. Não habilite uma configuração de versão diferente da executada pelo serviço FPM.

Testando a execução do PHP

Crie um arquivo temporário:

sudo nano /var/www/html/info.php

Adicione:

<?php
phpinfo();

Acesse http://IP_DO_SERVIDOR/info.php, substituindo pelo IP real. Se aparecer a página de informações do PHP, o Apache está encaminhando o script ao PHP-FPM.

Atenção: phpinfo() apresenta informações internas do ambiente, como caminhos, módulos e configurações. Não mantenha esse arquivo disponível publicamente. Remova-o depois do teste:

sudo rm /var/www/html/info.php

Esse procedimento testa a execução do PHP pelo Apache. Ele não testa uma conexão com o banco de dados.

Configurando o firewall

O UFW é utilizado com frequência no Ubuntu e também pode ser instalado no Debian. Antes de configurá-lo, verifique se já existe outro firewall ou uma política de rede administrada pelo provedor.

Instale o UFW, se necessário:

sudo apt install ufw -y

Verifique o estado atual:

sudo ufw status verbose

Defina as políticas padrão e permita HTTP e HTTPS:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Neste tutorial, o SSH é testado somente por localhost, por isso não liberamos a porta 22. Se você estiver conectado remotamente, crie e teste uma regra SSH adequada antes de ativar o firewall. Caso contrário, poderá perder o acesso ao servidor.

Ative o UFW somente depois de conferir as regras necessárias:

sudo ufw enable
sudo ufw status verbose
PortaProtocoloServiço
80TCPHTTP
443TCPHTTPS
22TCPSSH, quando o acesso remoto estiver configurado
3306TCPMySQL/MariaDB, normalmente restrito ao acesso local

Não libere a porta 3306 para a internet apenas para permitir que uma aplicação hospedada no mesmo computador acesse o banco. Nesse cenário, a comunicação pode permanecer local.

Verificando os serviços

Confira o SSH e o Apache:

sudo systemctl is-active ssh
sudo systemctl is-active apache2

No Ubuntu, confira o MySQL:

sudo systemctl is-active mysql

No Debian, confira o MariaDB:

sudo systemctl is-active mariadb

Identifique o serviço PHP-FPM instalado:

systemctl list-units --type=service 'php*-fpm.service'

O resultado esperado para os serviços instalados e iniciados é active. Valide também a configuração do Apache e consulte as portas em uso:

sudo apache2ctl configtest
sudo apache2ctl -S
sudo ss -lntup

Consultando os logs

Erros do Apache:

sudo tail -n 50 /var/log/apache2/error.log

Acessos ao Apache:

sudo tail -f /var/log/apache2/access.log

Para interromper o acompanhamento, pressione Ctrl + C.

Para consultar o PHP-FPM, substitua a versão pelo serviço encontrado:

sudo journalctl -u php8.3-fpm -n 50 --no-pager

No Ubuntu, consulte o MySQL:

sudo journalctl -u mysql -n 50 --no-pager

No Debian, consulte o MariaDB:

sudo journalctl -u mariadb -n 50 --no-pager

Problemas comuns durante a instalação

Apache não inicia

sudo apache2ctl configtest
sudo ss -lntp | grep ':80'
sudo journalctl -u apache2 -n 50 --no-pager

Se a porta 80 estiver ocupada, identifique o processo responsável antes de alterar a configuração.

PHP aparece como código-fonte no navegador

Isso pode indicar que o Apache não está encaminhando os arquivos PHP ao PHP-FPM. Não mantenha um servidor público nessa condição, pois o código-fonte pode ficar exposto.

php -v
sudo apache2ctl -M | grep proxy_fcgi
ls -l /etc/apache2/conf-enabled/ | grep fpm
systemctl list-units --type=service 'php*-fpm.service'

Confira se a configuração FPM correspondente à versão instalada está habilitada. Depois, valide a configuração e reinicie os serviços.

Apache apresenta erro 403 Forbidden

Verifique as permissões dos diretórios e as regras do Virtual Host:

namei -l /var/www/meusite
sudo apache2ctl -S

O Apache precisa conseguir atravessar os diretórios do caminho e ler os arquivos publicados.

Apache apresenta erro 404 Not Found

Confira o DocumentRoot e se o arquivo solicitado realmente existe:

sudo grep -R "DocumentRoot" /etc/apache2/sites-enabled/
ls -la /var/www/meusite/

MySQL ou MariaDB não inicia

No Ubuntu:

sudo systemctl status mysql
sudo journalctl -u mysql -n 100 --no-pager

No Debian:

sudo systemctl status mariadb
sudo journalctl -u mariadb -n 100 --no-pager

Não consigo acessar o SSH localmente

sudo systemctl status ssh
sudo journalctl -u ssh -n 50 --no-pager
ssh "$(whoami)"@localhost

Cuidados antes de colocar o servidor em produção

Uma instalação funcionando não significa que o computador esteja automaticamente preparado para receber tráfego público.

  1. Mantenha o Ubuntu ou Debian e os pacotes atualizados.
  2. Utilize senhas fortes nas contas administrativas.
  3. Evite acesso remoto direto ao usuário root.
  4. Configure SSH por chave e restrinja as origens de acesso quando houver administração remota.
  5. Configure HTTPS com certificado TLS válido.
  6. Não exponha a porta 3306 do banco sem necessidade.
  7. Utilize contas de banco com privilégios limitados.
  8. Configure backups e teste a restauração.
  9. Remova arquivos de diagnóstico, como info.php.
  10. Monitore os registros de acesso e erros.
  11. Conceda permissões de escrita somente aos diretórios que realmente precisam dela.
  12. Mantenha arquivos privados e credenciais fora do diretório público.

Instalando os componentes com um script Bash

O script a seguir automatiza a instalação básica em sistemas Ubuntu e Debian que utilizam APT e systemd. Ele identifica a distribuição, escolhe o banco de dados padrão definido neste tutorial, instala PHP e suas extensões, identifica a versão instalada do PHP-FPM e configura a integração com o Apache.

No Ubuntu, o script instala o pacote mysql-server. No Debian, instala mariadb-server. O script não configura firewall, não abre portas, não habilita SSH remoto, não altera Virtual Hosts existentes, não expõe o banco na rede e não cria usuários ou bancos para aplicações.

Script install.sh

O instalador abaixo foi separado do texto do artigo para evitar problemas de formatação. Ele:

  1. aceita somente Ubuntu e Debian com APT e systemd;
  2. instala Apache, OpenSSH, MySQL no Ubuntu ou MariaDB no Debian;
  3. instala PHP CLI, PHP-FPM e extensões comuns;
  4. identifica a versão do PHP-FPM e habilita a integração FastCGI no Apache;
  5. preserva os arquivos e Virtual Hosts existentes;
  6. registra a execução em /var/log/;
  7. não altera o firewall, não cria usuários ou bancos de aplicações e não configura DNS ou HTTPS.
#!/usr/bin/env bash
#
# Instala Apache2, OpenSSH, MySQL/MariaDB e PHP-FPM
# em Ubuntu e Debian com APT e systemd.
#
# Ubuntu: MySQL Server (pacote mysql-server)
# Debian: MariaDB Server (pacote mariadb-server)
#
# O script não configura firewall, DNS, HTTPS ou Virtual Hosts.
# Não sobrescreve arquivos do site.

set -Eeuo pipefail
IFS=$'\n\t'

LOG_FILE=""
DB_PACKAGE=""
DB_SERVICE=""
DB_CLIENT=""
PHP_VERSION=""
PHP_FPM_SERVICE=""
PHP_FPM_CONF=""

log() {
    printf '[INFO] %s\n' "$*"
}

die() {
    printf '[ERRO] %s\n' "$*" >&2
    exit 1
}

on_error() {
    local code=$?
    local line="${BASH_LINENO[0]:-desconhecida}"
    printf '\n[ERRO] Falha na linha %s. Código de saída: %s\n' "$line" "$code" >&2
    if [[ -n "$LOG_FILE" ]]; then
        printf '[ERRO] Consulte o log: %s\n' "$LOG_FILE" >&2
    fi
    exit "$code"
}
trap on_error ERR

require_root() {
    [[ "$EUID" -eq 0 ]] || die "Execute como administrador: sudo ./install.sh"
}

prepare_log() {
    LOG_FILE="/var/log/install-web-stack-$(date +%Y%m%d-%H%M%S).log"
    touch "$LOG_FILE" || die "Não foi possível criar o arquivo de log: $LOG_FILE"
    chmod 600 "$LOG_FILE"
    exec > >(tee -a "$LOG_FILE") 2>&1
}

detect_os() {
    [[ -r /etc/os-release ]] || die "Arquivo /etc/os-release não encontrado."
    # shellcheck disable=SC1091
    source /etc/os-release

    case "${ID:-}" in
        ubuntu)
            DB_PACKAGE="mysql-server"
            DB_SERVICE="mysql"
            DB_CLIENT="mysql"
            ;;
        debian)
            DB_PACKAGE="mariadb-server"
            DB_SERVICE="mariadb"
            DB_CLIENT="mariadb"
            ;;
        *)
            die "Distribuição não suportada: ${PRETTY_NAME:-${ID:-desconhecida}}."
            ;;
    esac

    command -v apt-get >/dev/null 2>&1 || die "apt-get não encontrado."
    command -v systemctl >/dev/null 2>&1 || die "systemctl não encontrado."
    [[ "$(ps -p 1 -o comm= | tr -d ' ')" == "systemd" ]] ||
        die "O processo PID 1 não é systemd. Este instalador requer systemd."

    log "Sistema detectado: ${PRETTY_NAME:-$ID}"
    log "Banco selecionado: $DB_PACKAGE"
}

install_packages() {
    log "Atualizando a lista de pacotes..."
    apt-get update

    log "Instalando Apache, SSH, banco de dados, PHP e extensões..."
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
        apache2 \
        openssh-server \
        "$DB_PACKAGE" \
        php \
        php-cli \
        php-fpm \
        php-common \
        php-curl \
        php-mbstring \
        php-xml \
        php-zip \
        php-gd \
        php-mysql
}

detect_php_fpm() {
    command -v php >/dev/null 2>&1 || die "PHP CLI não foi instalado."
    PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION, ".", PHP_MINOR_VERSION;')"
    PHP_FPM_SERVICE="php${PHP_VERSION}-fpm"
    PHP_FPM_CONF="php${PHP_VERSION}-fpm"

    systemctl cat "${PHP_FPM_SERVICE}.service" >/dev/null 2>&1 ||
        die "Serviço PHP-FPM não encontrado: ${PHP_FPM_SERVICE}. Verifique os pacotes instalados."

    [[ -f "/etc/apache2/conf-available/${PHP_FPM_CONF}.conf" ]] ||
        die "Configuração do Apache para ${PHP_FPM_CONF} não encontrada."

    log "Versão do PHP CLI detectada: $PHP_VERSION"
    log "Serviço PHP-FPM: $PHP_FPM_SERVICE"
}

configure_php_fpm() {
    log "Habilitando módulos FastCGI do Apache..."
    a2enmod proxy_fcgi setenvif

    log "Habilitando a configuração ${PHP_FPM_CONF}..."
    a2enconf "$PHP_FPM_CONF"

    systemctl enable --now "$PHP_FPM_SERVICE"
}

start_services() {
    log "Habilitando e iniciando os serviços..."
    systemctl enable --now ssh
    systemctl enable --now "$DB_SERVICE"
    systemctl enable --now apache2
    systemctl enable --now "$PHP_FPM_SERVICE"
}

validate_apache() {
    log "Validando a configuração do Apache..."
    apache2ctl configtest
    log "Reiniciando o Apache..."
    systemctl restart apache2
}

verify_installation() {
    local services=(
        ssh
        apache2
        "$DB_SERVICE"
        "$PHP_FPM_SERVICE"
    )
    local service

    log "Verificando os serviços..."
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            printf '[OK] %s está ativo\n' "$service"
        else
            printf '[ERRO] %s não está ativo\n' "$service" >&2
            return 1
        fi
    done

    apache2ctl configtest
    php --version
    "$DB_CLIENT" --version

    log "Módulos FastCGI habilitados:"
    apache2ctl -M | grep -E 'proxy_module|proxy_fcgi_module' || true

    log "Socket(s) PHP disponíveis:"
    find /run/php -maxdepth 1 -type s -name '*.sock' -print 2>/dev/null || true
}

main() {
    require_root
    prepare_log
    detect_os
    install_packages
    detect_php_fpm
    configure_php_fpm
    start_services
    validate_apache
    verify_installation

    log "Instalação concluída."
    log "Apache: http://IP_DO_SERVIDOR/"
    log "Banco de dados: $DB_SERVICE"
    log "PHP-FPM: $PHP_FPM_SERVICE"
    log "Log: $LOG_FILE"
    log "O firewall não foi alterado. Configure as regras conforme seu ambiente."
}

main "$@"

Como executar

Salve somente o conteúdo do bloco Bash em um arquivo chamado install.sh. Entre no diretório onde salvou o arquivo e execute:

chmod +x install.sh
sudo ./install.sh

O comando sudo solicitará a senha do usuário administrador, se necessário. A instalação depende de acesso aos repositórios APT. Acompanhe as mensagens e consulte o log indicado ao final. O instalador não cria uma página inicial nem sobrescreve o conteúdo existente em /var/www/html/.

Atenção: o script instala serviços e inicia o SSH, mas não configura acesso remoto, firewall, HTTPS, DNS, Virtual Hosts nem credenciais de aplicações. Revise a segurança antes de disponibilizar o computador na internet.

Conclusão

Com Apache2, SSH, um servidor de banco de dados e PHP-FPM instalados, Ubuntu e Debian passam a contar com os principais componentes utilizados na hospedagem de aplicações PHP.

O Apache recebe as requisições e entrega os arquivos localizados no DocumentRoot. O PHP-FPM executa os scripts PHP. O MySQL ou MariaDB fornece o serviço de banco de dados, enquanto o SSH permite administrar o terminal por uma conexão segura.

Também aprendemos a organizar projetos em /var/www/, configurar Virtual Hosts, identificar os principais arquivos e diretórios do Apache e verificar o funcionamento dos serviços.

Os comandos comuns podem ser utilizados tanto no Ubuntu Desktop quanto no Ubuntu Server e no Debian, desde que os pacotes e serviços estejam disponíveis nos repositórios e no sistema utilizado. As diferenças de versão do PHP e de implementação do banco de dados precisam ser consideradas, como explicado ao longo do tutorial.

Ao final, o computador estará preparado para receber projetos PHP. O desenvolvimento da aplicação, a criação de bancos específicos, a configuração das credenciais e a conexão entre PHP e o banco são etapas posteriores e não fazem parte deste tutorial.

Referências oficiais

  1. Ubuntu Server: documentação oficial
  2. Debian: documentação oficial
  3. Apache HTTP Server: documentação oficial
  4. PHP: documentação oficial em português
  5. MySQL: documentação oficial
  6. MariaDB: documentação oficial
  7. OpenSSH: manuais oficiais
  8. Debian Manpages