EQVPS
PainelComeçar

Como instalar o MySQL num VPS: usuários, acesso remoto seguro, menos RAM e backups

Instale o MySQL 8.0 num VPS com Ubuntu 24.04, crie um banco e um usuário para o app, acesse do seu computador sem abrir a porta 3306, reduza a memória em repouso de 383 MB para 165 MB e faça backup toda noite com um script que falha de forma visível.

Instalar o MySQL leva um comando. A maior parte do trabalho vem depois: um usuário para o app, um jeito de chegar ao banco a partir do seu computador sem colocar a porta 3306 na internet, ajustes de memória para um servidor pequeno e backups que rodam sem você. Este guia cobre os quatro no Ubuntu 24.04. Cada passo foi executado na nossa imagem do Ubuntu 24.04, e os números abaixo vêm desse servidor.

Rode os comandos com um usuário que tenha sudo. O guia de configuração do Ubuntu cria um.

1. Instale

sudo apt update
sudo apt install -y mysql-server
mysql --version

A instalação levou 51 segundos no nosso servidor e trouxe o MySQL 8.0.46. Ele já inicia, volta a iniciar a cada boot e escuta só no próprio servidor: 127.0.0.1:3306 para conexões normais e 127.0.0.1:33060 para o protocolo X, mais novo. Por enquanto nada fica acessível de fora.

2. Crie um banco e um usuário

A conta root do MySQL usa autenticação por socket no Ubuntu, então sudo mysql entra sem senha. Crie um banco e um usuário para o seu app:

sudo mysql
CREATE DATABASE app CHARACTER SET utf8mb4;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';
EXIT;

Teste do jeito que o app vai conectar:

mysql -u app -p app -e "SELECT CURRENT_USER();"

Deve aparecer app@localhost. Uma senha errada recebe ERROR 1045 (28000): Access denied for user 'app'@'localhost'. O usuário pode fazer tudo dentro de app e nada fora dele.

3. Conecte do seu computador: túnel SSH

Para usar um cliente de desktop como DBeaver, MySQL Workbench ou a linha de comando mysql na sua máquina, não abra porta nenhuma. Redirecione uma pelo SSH:

ssh -L 3307:127.0.0.1:3306 deploy@YOUR.SERVER.IP

Num plano NAT, acrescente -p e a porta SSH pessoal do painel. Enquanto essa janela estiver aberta, aponte o cliente para o host 127.0.0.1, porta 3307, usuário app. Usamos 3307 do lado local para não bater com um MySQL que você talvez rode no seu computador. No nosso teste o servidor respondeu pelo túnel na hora, enquanto uma conexão direta ao endereço dele na 3306 foi recusada.

4. Acesso direto para outro servidor

Às vezes o app roda num segundo servidor e precisa conectar direto. Para isso o banco precisa de um plano com IPv4 próprio, porque um plano NAT só redireciona a sua porta SSH. São três mudanças, todas limitadas ao endereço do servidor do app (aqui 203.0.113.20):

sudo sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
sudo systemctl restart mysql
sudo ufw allow from 203.0.113.20 to any port 3306 proto tcp
CREATE USER 'app'@'203.0.113.20' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'203.0.113.20';

Se o ufw ainda não estiver ativo, libere o SSH primeiro (sudo ufw allow OpenSSH) e depois rode sudo ufw enable. O guia do ufw tem os detalhes.

Conferimos as duas travas separadamente. Com a regra do firewall, mas sem um usuário do MySQL correspondente, o servidor recusou com error 1130: Host '…' is not allowed to connect to this MySQL server. Com o usuário criado, a conexão passou. Sem a regra do firewall, a conexão simplesmente estourou o tempo limite. Qualquer outro endereço na internet recebe esse mesmo tempo esgotado.

5. Use menos RAM

Em repouso, sem dados próprios, o MySQL 8.0 usava 383 MB no nosso servidor. A maior parte é o Performance Schema, um recurso de diagnóstico que reserva memória antecipadamente. Num VPS pequeno, desligue-o e defina você mesmo o tamanho do cache principal:

sudo tee /etc/mysql/mysql.conf.d/zz-small-vps.cnf >/dev/null <<'EOF'
[mysqld]
performance_schema = OFF
innodb_buffer_pool_size = 256M
max_connections = 50
EOF
sudo systemctl restart mysql
ps -o rss= -C mysqld

Depois de reiniciar, ele usava 165 MB. O buffer pool guarda em cache seus dados e índices, e 256 MB servem para um servidor de 2 GB que também roda o app. Aumente se o banco for a principal coisa do servidor e já tiver passado do tamanho do cache. max_connections = 50 é de sobra para um app com pool de conexões. Você perde as estatísticas do performance_schema. Ligue de novo se um dia precisar investigar consultas lentas a fundo.

6. Backups noturnos

O mysqldump --single-transaction tira uma cópia consistente das tabelas InnoDB sem travar o app. Coloque-o num script pequeno:

sudo tee /usr/local/bin/mysql-backup >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
umask 077
mkdir -p /var/backups/mysql
mysqldump --single-transaction --routines --triggers app | gzip > /var/backups/mysql/app-$(date +%F).sql.gz
find /var/backups/mysql -name 'app-*.sql.gz' -mtime +14 -delete
EOF
sudo chmod 755 /usr/local/bin/mysql-backup
echo '0 3 * * * root /usr/local/bin/mysql-backup' | sudo tee /etc/cron.d/mysql-backup
sudo /usr/local/bin/mysql-backup && sudo ls -l /var/backups/mysql

Cada linha tem um motivo:

  • umask 077 deixa o dump legível só para o root (-rw-------), já que ele guarda todos os seus dados.
  • pipefail faz o script inteiro falhar se o mysqldump falhar. Sem isso, o gzip gravaria um arquivo minúsculo e vazio e diria que deu tudo certo. Quebramos o comando de propósito e o script terminou com código 2, como deve.
  • find … -mtime +14 -delete mantém duas semanas de cópias.
  • O script roda como root, então o mysqldump entra pelo socket e nenhuma senha fica num arquivo.

Backup que você nunca restaurou ainda não conta. Restaure num banco temporário e olhe os dados:

sudo mysql -e "CREATE DATABASE app_restore"
gunzip -c /var/backups/mysql/app-2026-10-25.sql.gz | sudo mysql app_restore
sudo mysql -e "SHOW TABLES FROM app_restore"
sudo mysql -e "DROP DATABASE app_restore"

No nosso teste, a tabela restaurada tinha as mesmas linhas da original. Cópias no mesmo disco não protegem se você perder o servidor, então leve-as de vez em quando para outra máquina com scp ou restic. O Managed Backups soma pontos de restauração diários do servidor inteiro.

Qual plano

O Micro (2 vCPU, 2 GB, 25 GB, $5/mês) aguenta o MySQL ajustado como acima mais um app web. Se o banco em si passar de alguns gigabytes, o Small, com 4 GB e 35 GB por $8/mês, deixa você dar 1 GB ou mais ao buffer pool. Os dois são planos NAT, e o túnel SSH do passo 3 funciona neles. O passo 4 exige IPv4 próprio: o Micro-IP custa $10/mês.

Prefere PostgreSQL? O guia do PostgreSQL segue o mesmo roteiro. Todos os planos estão em VPS, e o pagamento é em USDT, USDC ou ETH nas redes Base, Ethereum ou Polygon.

Perguntas frequentes

MySQL ou MariaDB?

Os dois estão nos repositórios do próprio Ubuntu 24.04: mysql-server instala o MySQL 8.0 e mariadb-server instala o MariaDB 10.11. A maioria dos apps que pedem "MySQL" funciona com qualquer um. Use o que a documentação do seu app indicar, e o MySQL 8.0 se tanto faz. Este guia usa MySQL.

Qual é a senha de root do MySQL?

Não existe. No Ubuntu, a conta root do MySQL usa autenticação por socket: sudo mysql entra como root, e ninguém consegue entrar como root pela rede. Deixe assim e crie usuários separados para os seus apps.

Devo abrir a porta 3306 para a internet?

Não. Portas de banco abertas são varridas e recebem tentativas de senha o tempo todo. Do seu computador, conecte por um túnel SSH. Se outro servidor precisar conectar direto, libere só o IP dele, tanto no MySQL quanto no firewall.

Quanta RAM o MySQL precisa?

Logo depois da instalação, o MySQL 8.0 usava 383 MB no nosso servidor de teste, sem bancos próprios. Desligando o Performance Schema e com um buffer pool modesto, caiu para 165 MB. O plano Micro de 2 GB roda MySQL e um app com folga; com esse ajuste, 1 GB serve para um site pequeno.

Preciso rodar o mysql_secure_installation?

No Ubuntu 24.04 quase todo o trabalho dele já está feito. Nossa instalação nova não tinha usuários anônimos nem banco de teste, e o root só entra pelo socket local. Rode se quiser o componente de verificação de força de senha que ele oferece; senão, pode pular.

Comentários

Nenhum comentário ainda. Seja o primeiro.

Deixe um comentário

Os comentários são moderados antes de aparecerem.