Tutoriais de VPS
Implantar o GitLab CE em uma VPS (2026): tutorial completo de Docker Compose, HTTPS, SSH, backup e Runner
Implante o GitLab CE em uma VPS com Docker Compose, configure HTTPS com domínio, portas SSH, primeiro login, otimização para máquinas modestas, backup e atualização, e a configuração do GitLab Runner, além de solucionar problemas comuns de inicialização e clonagem.

Implantar o GitLab CE em uma VPS (2026): tutorial completo de Docker Compose, HTTPS, SSH, backup e Runner
Se você quer montar o GitLab em uma VPS, não saia copiando um único docker run. O GitLab junta repositórios de código, Merge Requests, Issues, Container Registry e CI/CD em um só sistema, e o preço disso é consumir mais recursos que o Gitea e depender mais de domínios, portas e backups corretos.
Este artigo usa a imagem oficial GitLab CE 19.2.1, implantada via Docker Compose. O SSH do host continua usando a 22, enquanto a clonagem por SSH do GitLab passa para a 2222; o lado web é servido diretamente por HTTPS pelo Nginx integrado do GitLab e pelo Let's Encrypt. O Runner fica em outra VPS, para que as tarefas de build não derrubem o repositório de código.
A linha de base oficial do GitLab para um nó único comum é 8 vCPU e 16GB de memória; a opção com memória limitada pode cair para 2GB de memória mais 1GB de Swap, mas fica limitada a cerca de 5 desenvolvedores e repositórios com menos de 100MB, e pode ficar bem mais lenta. Na prática, dá para ver assim:
| Uso | Configuração sugerida | Observações |
|---|---|---|
| Teste temporário, repositórios pessoais pequenos | 2–4 vCPU, 4GB de memória, 40GB SSD | Exige ajuste de memória baixa; não é recomendado rodar o Runner ao mesmo tempo |
| Uso diário de uma equipe pequena | 4 vCPU, 8GB de memória, 80GB NVMe | Mais adequado como configuração inicial |
| CI intenso, Registry, muitos artefatos | 8 vCPU, 16GB ou mais | Melhor separar o Runner e o armazenamento de objetos |
A leitura/gravação aleatória de SSD/NVMe importa mais do que simplesmente empilhar CPU. Se você ainda não decidiu a configuração, pode consultar primeiro o guia de escolha de configuração de VPS. Se você só precisa de um repositório Git privado leve e não precisa de uma plataforma DevOps completa, o tutorial de instalação do Gitea costuma sair mais em conta.
Também não calcule o disco apenas pelo código-fonte dos repositórios. O banco de dados, o LFS, os Packages, o Container Registry, os logs de CI e os Artifacts crescem, e o backup também precisa de espaço temporário extra. Antes de colocar em produção, liste o número previsto de usuários, o tamanho total dos repositórios, os artefatos por build e os dias de retenção, e deixe no disco pelo menos espaço para um backup completo. Um disco cheio costuma parar o GitLab antes de uma CPU insuficiente.
Primeiro aponte os registros A/AAAA de gitlab.example.com para o endereço público da VPS. Troque o domínio e o e-mail abaixo pelos seus; durante a validação do Let's Encrypt, a 80 e a 443 precisam estar acessíveis pela internet pública.
Verifique o uso das portas:
sudo ss -lntup | grep -E ':22|:80|:443|:2222'
A 22 deve continuar sendo usada pelo SSH do host, enquanto a 80, a 443 e a 2222 ficam para o contêiner do GitLab. Crie os diretórios persistentes:
sudo mkdir -p /srv/gitlab/{config,logs,data}
sudo mkdir -p /srv/gitlab-backups
Antes de configurar o UFW, mantenha a sessão SSH atual aberta e teste em um terminal novo, para não se trancar para fora:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2222/tcp
sudo ufw enable
sudo ufw status numbered
O grupo de segurança do provedor de nuvem também precisa liberar as mesmas portas. Se você não tem familiaridade com a operação, consulte primeiro o tutorial de UFW para evitar bloqueio do SSH.
Depois de instalar o Docker no Ubuntu ou Debian, confirme primeiro que o serviço e o plugin do Compose estão disponíveis:
sudo systemctl enable --now docker
docker --version
docker compose version
df -h /srv/gitlab
O GitLab não oferece suporte oficial para levar este exemplo de produção diretamente para o Docker Desktop for Windows. Em um servidor de produção, também não coloque o diretório de dados em sistemas de arquivos de rede de alta latência, como NFS ou EFS; o Gitaly é muito sensível a E/S aleatória.
Crie o diretório do projeto e o arquivo Compose:
sudo mkdir -p /opt/gitlab
cd /opt/gitlab
sudo nano compose.yaml
Escreva a seguinte configuração:
services:
gitlab:
image: gitlab/gitlab-ce:19.2.1-ce.0
container_name: gitlab
restart: always
hostname: gitlab.example.com
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.example.com'
gitlab_rails['gitlab_shell_ssh_port'] = 2222
letsencrypt['enable'] = true
letsencrypt['contact_emails'] = ['[email protected]']
ports:
- '80:80'
- '443:443'
- '2222:22'
volumes:
- /srv/gitlab/config:/etc/gitlab
- /srv/gitlab/logs:/var/log/gitlab
- /srv/gitlab/data:/var/opt/gitlab
shm_size: '256m'
logging:
driver: json-file
options:
max-size: '20m'
max-file: '5'
Aqui você precisa alterar ao mesmo tempo hostname, external_url, o e-mail de contato e o DNS. 2222:22 é o mapeamento da porta do host para a porta SSH do contêiner, enquanto gitlab_shell_ssh_port = 2222 é responsável por fazer a página web gerar a Clone URL correta; omitir qualquer um deles fará os usuários se conectarem à porta errada.
Verifique primeiro o resultado renderizado e depois inicie:
docker compose config
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200 gitlab
Não use latest em produção. Fixar a versão de patch não só evita uma atualização repentina ao reconstruir, como também restaurar um backup exige exatamente a mesma versão do GitLab e o mesmo tipo CE/EE. Para verificações de integridade, logs e princípios de reversão do Compose, consulte a lista de verificação de configuração de produção do Docker Compose.
O GitLab precisa de alguns minutos para inicializar o banco de dados e os serviços internos na primeira vez. O contêiner mostrar running não significa que a página já esteja disponível; se você vir 502 por um tempo, verifique primeiro o progresso:
docker exec -it gitlab gitlab-ctl status
docker compose logs --tail=200 gitlab
curl -I https://gitlab.example.com
Se o Let's Encrypt falhar, confirme primeiro que o domínio já está ativo no DNS público, que a 80/443 não está bloqueada pelo grupo de segurança e que não há um registro CAA incorreto. Não use um example.com que não possa ser resolvido publicamente para realmente solicitar um certificado.
Quando a página funcionar, leia a senha temporária de root:
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
O nome de usuário é root. Após entrar, altere a senha imediatamente, preencha o e-mail do administrador e crie uma conta comum para o uso diário. Esse arquivo de senha temporária é excluído automaticamente 24 horas após a primeira reinicialização, então não copie a senha para scripts ou históricos de chat.
Primeiro crie um projeto vazio no GitLab e depois faça um push por HTTPS. Em seguida, adicione sua chave pública SSH local em Preferences → SSH Keys no menu do avatar e teste:
ssh -T -p 2222 [email protected]
A primeira conexão vai perguntar se você aceita a Host Key; confira a impressão digital antes de confirmar. O endereço SSH correto deve ser parecido com:
ssh://[email protected]:2222/your-name/demo.git
Se a página ainda mostrar 22, verifique a grafia de gitlab_shell_ssh_port e reconstrua o contêiner; se a 2222 for recusada, verifique em ordem docker compose ps, ss -lntup, o UFW e o grupo de segurança da nuvem. Não mapeie a 22 do contêiner para a 22 do host só para facilitar, senão vai conflitar com o SSH que você usa para gerenciar a VPS.
Uma VPS de 4GB só é adequada para uso pessoal e de baixa frequência. Você pode acrescentar as três linhas abaixo ao GITLAB_OMNIBUS_CONFIG do Compose e depois reconstruir o contêiner:
puma['worker_processes'] = 0
sidekiq['concurrency'] = 10
prometheus_monitoring['enable'] = false
docker compose up -d
docker exec -it gitlab gitlab-ctl status
free -h
docker stats --no-stream gitlab
O Puma em processo único reduz a concorrência, uma concorrência menor do Sidekiq faz as tarefas em segundo plano se acumularem, e desativar o Prometheus integrado também remove a capacidade de monitoramento. O Swap pode reduzir o risco de OOM repentino, mas, uma vez que a paginação continua, o GitLab fica muito lento. Quando o Puma ou o Sidekiq reiniciarem repetidamente ou aparecerem registros de OOM do kernel, priorize aumentar a memória em vez de continuar desligando serviços essenciais.
A imagem Docker do GitLab não inclui um serviço SMTP. Sem e-mail, convites, redefinições de senha, alertas e notificações de backup são afetados; convém conectar um SMTP confiável na configuração do Omnibus e enviar um e-mail de teste pelo Rails Console ou pelo painel de administração.
Após entrar em produção, conclua pelo menos estas configurações:
- Desative o cadastro de usuários quando você não precisar de uma comunidade pública;
- Ative a autenticação de dois fatores para administradores e mantenedores;
- Restrinja a visibilidade dos projetos e as permissões padrão;
- Verifique periodicamente administradores, Access Tokens, Deploy Keys e Runners;
- Não rode o Runner no mesmo host do GitLab e não use executores privilegiados para projetos não confiáveis.
Também verifique no Admin Area a visibilidade padrão dos projetos, as permissões de novos usuários e a política de retenção máxima de Artifacts. Se realmente precisar habilitar o cadastro público, pelo menos combine com verificação por e-mail, aprovação do administrador e limitação de frequência. Depois de configurar o SMTP, não se limite a ver que salvou com sucesso; dispare de fato um e-mail de redefinição de senha e confirme que o domínio do remetente, os retornos e a política de spam estão normais.
Crie um backup dos dados de negócio:
docker exec -t gitlab gitlab-backup create
ls -lh /srv/gitlab/data/backups
Esse arquivo contém dados como o banco de dados, os repositórios, os uploads e os artefatos, mas não equivale a um backup da máquina inteira. A configuração, o gitlab-secrets.json, as chaves privadas TLS e as SSH Host Keys continuam em /srv/gitlab/config e precisam ser guardados separadamente:
sudo tar -C /srv/gitlab -czf \
/srv/gitlab-backups/gitlab-config-$(date +%F).tar.gz config
sudo ls -lh /srv/gitlab-backups
Se você usar armazenamento de objetos externo, o gitlab-backup também não vai copiar o Bucket por você. Sincronize os dois tipos de backup com outro servidor ou outro armazenamento de objetos e faça simulações de restauração com regularidade; ver apenas os arquivos de backup não conta como recuperável. Para a abordagem completa, consulte simulação de backup e restauração em VPS.
Recomenda-se manter três tipos de ponto de restauração —"diário, semanal, antes de atualizar"— e registrar o tag do GitLab correspondente a cada backup. Após sincronizar, verifique no lado remoto o tamanho ou o checksum do arquivo, para que, se o disco local for danificado, você não perca os backups junto. Quando Registry, LFS ou Artifacts usarem um Bucket externo, o backup de negócio e o snapshot do armazenamento de objetos devem estar na mesma janela de manutenção, para reduzir inconsistências de referência após a restauração.
Antes de restaurar, prepare um GitLab novo funcionando normalmente e com exatamente a mesma versão e Edition. Pare o Puma e o Sidekiq antes de executar a restauração:
docker exec -it gitlab gitlab-ctl stop puma
docker exec -it gitlab gitlab-ctl stop sidekiq
docker exec -it gitlab gitlab-backup restore BACKUP=REPLACE_WITH_BACKUP_ID
docker restart gitlab
docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true
A restauração reescreve o banco de dados, então só pode ser executada em uma janela de manutenção ou em uma máquina isolada de simulação de restauração. Antes de restaurar, também é preciso restaurar a configuração e os Secrets correspondentes.
Antes de atualizar, registre a versão atual, conclua um backup e consulte a Upgrade Path oficial do GitLab. Ao cruzar várias versões menores ou maiores, você precisa passar pelas versões de parada designadas; as paradas do GitLab 19 incluem 19.2, 19.5, 19.8 e 19.11, e em cada etapa é preciso esperar as migrações em segundo plano terminarem.
Ao atualizar um patch dentro da mesma versão menor, primeiro altere a imagem no Compose para o tag fixado de destino e depois execute:
docker compose pull
docker compose up -d
docker compose logs --tail=200 gitlab
docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true
Em seguida, verifique a página web, o push por SSH, o Runner e as migrações em segundo plano. Depois que o banco de dados foi migrado, você não pode reverter apenas trocando o tag da imagem de volta para a versão antiga; uma reversão correta exige restaurar a imagem antiga, a configuração antiga e o backup da versão correspondente.
O Runner executa código dos projetos, então é melhor colocá-lo em uma VPS separada. Primeiro crie um Runner na página de Runners do projeto, do grupo ou do administrador no GitLab e obtenha o Runner Authentication Token que começa com glrt-. O fluxo antigo de Registration Token está obsoleto, então não copie tutoriais antigos.
Inicie um contêiner de versão fixada na VPS do Runner:
sudo mkdir -p /srv/gitlab-runner/config
docker run -d --name gitlab-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:alpine-v19.2.1
docker exec -it gitlab-runner gitlab-runner register \
--non-interactive \
--url 'https://gitlab.example.com' \
--token 'glrt-REPLACE_WITH_RUNNER_AUTH_TOKEN' \
--executor docker \
--docker-image alpine:3.22 \
--description 'vps-docker-runner'
Verifique com um .gitlab-ci.yml mínimo:
stages: [test]
runner-check:
stage: test
image: alpine:3.22
script:
- echo "GitLab Runner is working"
- uname -a
Montar o Docker Socket significa que o Runner pode controlar o daemon Docker do host, o que não é isolamento forte. Deixe apenas projetos confiáveis usarem e não compartilhe esse Runner com projetos públicos. Quando precisar de cache, build de imagens e isolamento de segurança mais fino, você pode consultar o guia de Runner auto-hospedado do GitHub Actions para entender riscos semelhantes.
| Sintoma | O que verificar primeiro | Causa comum |
|---|---|---|
| A página mostra 502 por muito tempo | gitlab-ctl status, logs do contêiner, memória | Inicialização não concluída, OOM, falha de serviço interno |
| Falha na solicitação do certificado HTTPS | DNS, 80/443, CAA | Domínio ainda não ativo ou porta de validação bloqueada |
| O endereço SSH ainda mostra 22 | GITLAB_OMNIBUS_CONFIG | gitlab_shell_ssh_port não definido ou não aplicado |
| Conexão à 2222 recusada | Portas do Compose, UFW, grupo de segurança | Porta não mapeada ou regra de firewall ausente |
| O Runner fica offline | Logs do Runner, URL, certificado | URL errada, Token errado ou cadeia de certificados não confiável |
| O Job fica pending | Scope do Runner, tags, estado de pausa | O projeto não tem um Runner online compatível |
| O backup não pode ser restaurado | Versão, CE/EE, Secrets | Versão de destino diferente ou backup de configuração ausente |
A ordem geral de diagnóstico é ver primeiro os recursos, depois o estado do contêiner e por fim os logs do serviço correspondente:
free -h
df -h
docker compose ps
docker compose logs --tail=200 gitlab
docker exec -it gitlab gitlab-ctl tail
docker logs --tail=200 gitlab-runner
- Se você precisa de hospedagem de código, MR, permissões, Registry e CI/CD tudo em um, escolha o GitLab, mas prepare memória suficiente e tempo de manutenção.
- Se você só precisa de Git privado leve, Issues e colaboração básica, escolha o Gitea, mais tranquilo em uma VPS modesta.
- Se você mantém o código no GitHub e só quer controlar a máquina de build, escolha o Runner auto-hospedado do GitHub Actions.
Primeiro conclua quatro coisas em uma VPS não crítica: login por HTTPS, push por SSH, um Job de CI mínimo e restauração em outra máquina. Quando as quatro funcionarem, migre os repositórios de produção; caso contrário, "o contêiner consegue iniciar" ainda está muito longe de um GitLab utilizável.