Pular para o conteúdo principal

Migrar da Máquina (Host) para Docker

Se você possui o painel instalado diretamente na máquina (/var/www/jexactyl ou /var/www/pterodactyl) e deseja migrar para a stack Docker Compose oficial, siga o passo a passo simplificado e seguro abaixo.

Coexistência Segura com o Host

A stack Docker roda em uma rede bridge própria e isolada (jexactyl). Ela não publica as portas 3306 (MariaDB) nem 6379 (Redis) para a máquina, permitindo que bancos de dados de jogos e instâncias existentes no servidor continuem funcionando sem qualquer interferência. A porta padrão HTTP do painel no Docker é 8085, evitando conflito com o daemon Wings (que utiliza a porta 8080).


1. Fazer Backup do Banco e do .env no Host​

Preserve idênticos APP_KEY e HASHIDS_SALT!

As variáveis APP_KEY e HASHIDS_SALT do seu .env atual devem ser copiadas exatamente iguais para o .env do Docker. A troca da APP_KEY invalida dados criptografados e tokens de API no banco de dados.

Antes de exportar os dados, pause o worker de filas para evitar novas escritas:

# 1. Parar temporariamente o serviço de filas do painel no host
sudo systemctl stop panel.service
# Se não funcionar, tente:
# sudo systemctl stop pteroq.service
# sudo systemctl stop ptero.service

# 2. Exportar o banco de dados atual do painel (carrega o nome direto do .env, sem trocar manualmente)
export DB_DATABASE=$(grep -E '^DB_DATABASE=' /var/www/jexactyl/.env | cut -d '=' -f2 | tr -d "\"' " | xargs)
mariadb-dump -u root -p "$DB_DATABASE" > ~/painel-backup.sql
# Se o comando não existir, tente:
# mysqldump -u root -p "$DB_DATABASE" > ~/painel-backup.sql

# 3. Validar a integridade do dump gerado
tail -n 5 ~/painel-backup.sql
# Certifique-se de ver a mensagem: -- Dump completed on ...
grep -c "CREATE TABLE" ~/painel-backup.sql

# 4. Salvar cópia do .env original
sudo cp /var/www/jexactyl/.env ~/env.host.bak
# Caso o caminho da sua instalação seja pterodactyl:
# sudo cp /var/www/pterodactyl/.env ~/env.host.bak
Os arquivos dos servidores de jogos precisam ser migrados?

Não. Todos os servidores de jogos, uploads, arquivos e backups dos clientes são gerenciados exclusivamente pelo daemon Wings nos nós (/var/lib/pterodactyl/volumes/). A migração do painel afeta apenas o banco de dados e a interface web; seus servidores e dados nas Wings continuam funcionando normalmente sem qualquer alteração.


2. Clonar o Repositório Jexactyl-BR e Configurar o .env​

Você pode clonar o projeto diretamente no diretório desejado (por exemplo, /var/www/jexactyl-docker):

sudo git clone https://github.com/Next-Panel/Jexactyl-BR.git /var/www/jexactyl-docker
sudo chown -R $(id -un):$(id -gn) /var/www/jexactyl-docker
cd /var/www/jexactyl-docker
cp .env.example .env

Abra o arquivo .env para edição (nano .env) e configure os campos:

  • APP_KEY e HASHIDS_SALT: Copie exatamente os mesmos valores salvos em ~/env.host.bak.
  • PANEL_PORT: Mantenha 127.0.0.1:8085 (para receber conexões do Caddy ou Nginx local sem colidir com a porta 8080 do Wings).
  • APP_URL: URL pública do seu painel (ex: https://painel.seudominio.com.br).
  • TRUSTED_PROXIES: Mantenha *.
  • DB_DATABASE, DB_USERNAME e DB_PASSWORD: Configure as credenciais do banco para o container MariaDB.
  • PANEL_ADMIN_EMAIL e PANEL_ADMIN_PASSWORD: Deixe em branco, pois os usuários administradores já existem no banco de dados que será importado.

3. Subir o Banco no Docker e Importar o Backup​

Inicie primeiro os serviços de banco e cache:

# Sobe o MariaDB e o Redis
docker compose up -d database cache

# Aguarda o container database ficar com status saudável (healthy)
docker compose ps

Assim que o container database estiver com status (healthy), importe o dump:

Não substitua os $ manualmente

Cole o comando exatamente como está. As variáveis $MYSQL_USER, $MYSQL_PASSWORD e $MYSQL_DATABASE não são do seu terminal — elas existem dentro do container database (vêm do seu .env: DB_USERNAME / DB_PASSWORD / DB_DATABASE). As aspas simples por fora impedem o seu shell de expandir; as aspas duplas por dentro deixam o sh do container expandir. Nada para trocar à mão.

docker compose exec -T database sh -c 'mariadb -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' < ~/painel-backup.sql

# Valide a importação:
docker compose exec -T database sh -c 'mariadb -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "SELECT COUNT(*) FROM users;"'
docker compose exec -T database sh -c 'mariadb -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "SELECT COUNT(*) FROM servers;"'

4. Subir o Painel (Migrações Automáticas)​

# Inicia o painel
docker compose up -d panel
docker compose logs -f panel
Migração Automática de Tabelas (v3 para v4)

Durante a inicialização do container panel, o entrypoint executará automaticamente o comando php artisan migrate --isolated --seed --force. Ele adaptará todas as tabelas importadas da versão anterior para o schema moderno da v4, sem qualquer necessidade de comandos manuais no terminal.


5. Desativar a Rota Antiga do Host​

Desative a rota antiga do Host

Desative a rota antiga que servia /var/www/jexactyl ou /var/www/pterodactyl (PHP-FPM) no Apache, Caddy ou Nginx. Manter as duas ativas causa conflito: o servidor web continua entregando o painel antigo em vez do container em 127.0.0.1:8085.

Remova ou comente o bloco antigo que apontava para o PHP-FPM em /etc/caddy/Caddyfile (ou em /etc/caddy/conf.d/painel.caddy):

sudo nano /etc/caddy/Caddyfile

Apague ou comente o bloco parecido com:

# painel.seudominio.com.br {
# root * /var/www/jexactyl/public
# php_fastcgi unix//run/php/php8.1-fpm.sock
# file_server
# }

Valide que não restou rota do Host:

sudo grep -rn "var/www/jexactyl\|var/www/pterodactyl\|php.*fpm.sock" /etc/caddy/Caddyfile /etc/caddy/conf.d/ 2>/dev/null || echo "sem rota antiga"

6. Configurar o Proxy Reverso​

Selecione abaixo o servidor web instalado na sua máquina para apontar as requisições para a porta interna do container (127.0.0.1:8085):

Adicione ou edite o bloco do painel em /etc/caddy/Caddyfile (ou /etc/caddy/conf.d/painel.caddy):

painel.seudominio.com.br {
request_body {
max_size 100MB
}
reverse_proxy 127.0.0.1:8085
}

Valide e recarregue o Caddy:

sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy

Por fim, desative o serviço de fila legado do host para não consumir recursos desnecessários da máquina:

sudo systemctl disable --now panel.service
# Se não funcionar, tente:
# sudo systemctl disable --now pteroq.service
# sudo systemctl disable --now ptero.service

7. Configurar Backup Periódico no Crontab​

Crie o diretório de destino e edite o crontab do root:

sudo mkdir -p /backups/databases
sudo crontab -e
# Backup diário do banco do Docker à meia-noite (00:00)
0 0 * * * docker compose -f /var/www/jexactyl-docker/docker-compose.yml exec -T database sh -c 'mariadb-dump -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' > /backups/databases/jexactyl-backup-$(date +\%F).sql

# (Opcional) Dumps em intervalos menores (ex: a cada 40 minutos)
*/40 * * * * docker compose -f /var/www/jexactyl-docker/docker-compose.yml exec -T database sh -c 'mariadb-dump -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' > /backups/databases/jexactyl-backup.sql

8. Solução de Problemas: Boot Loop 1050 Table Already Exists​

Se o painel veio de uma linhagem antiga (ex.: /var/www/jexactyl ou /var/www/pterodactyl com histórico de migrations diferente do código atual), o primeiro boot do container panel pode entrar em loop com:

SQLSTATE[42S01]: Base table or view already exists: 1050 Table '...' already exists

Causa: a tabela migrations importada registra os nomes antigos; os arquivos novos com outro nome tentam recriar tabelas que já existem. O procedimento abaixo marca como executadas somente as migrations cujo efeito já existe, deixando as demais rodarem normalmente:

cd /var/www/jexactyl-docker
docker compose stop panel

# Repita até ver "Nothing to migrate": cada rodada aplica o que falta
# e para na próxima migration conflitante
docker compose run --rm --no-deps panel php artisan migrate --force

Para cada migration que falhar com already exists / Duplicate column (e somente nesses casos), marque-a como executada — primeiro confira que a tabela/coluna realmente existe:

# Exemplo: confere a tabela e marca a migration como executada
docker compose exec -T database sh -c 'mariadb -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "SHOW COLUMNS FROM admin_roles;"'
docker compose exec -T database sh -c 'mariadb -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "INSERT INTO migrations (migration, batch) VALUES ('"'"'2020_09_25_021109_create_admin_roles_table'"'"', (SELECT * FROM (SELECT COALESCE(MAX(batch),0)+1 FROM migrations) t));"'

Se a falha for de outro tipo (ex.: 1091 Can't DROP COLUMN), compare a migration com a tabela real: quando o estado final já existe (coluna a adicionar já presente, coluna a remover já ausente), marcar como executada é seguro; caso contrário, pare e investigue antes de continuar.

# Quando terminar, suba o painel normalmente
docker compose up -d panel
docker compose logs -f panel
Backup de reversão

Antes de importar, faça cópia nível-arquivo do volume do banco (não exige senha):

docker volume create backup-pre-migracao
docker run --rm -v jexactyl_db-data:/from:ro -v backup-pre-migracao:/to ubuntu:22.04 cp -a /from/. /to/

Para reverter: pare panel e database, copie de volta (/from = backup, /to = jexactyl_db-data) e suba tudo.