Tutorial completo para transformar um Dell Inspiron 15 Gamer antigo em um servidor local privado com Ubuntu Server, Docker, Caddy, Tailscale, domínios locais e deploy automático via GitHub Actions.
00 / Objetivo
O objetivo é transformar o Dell Inspiron 15 Gamer em um servidor local para dois projetos pessoais: Atlas e Ledger. O servidor ficará privado, preferencialmente sem nenhuma porta aberta no roteador. Ele poderá acessar a internet para consumir APIs, mas não ficará exposto publicamente.
PC principal / celular
↓
atlas.local / ledger.local
↓
DNS local ou hosts
↓
Notebook Dell servidor — 192.168.0.50
↓
Caddy reverse proxy
↓
Containers Docker
├── Atlas
└── Ledger
**
Acessa os projetos quando estiver na mesma rede Wi-Fi/cabo da casa.
http://atlas.local
http://ledger.local
**
Acessa de fora usando Tailscale, sem abrir porta no roteador.
http://atlas.home.arpa ou IP Tailscale
http://ledger.home.arpa ou IP Tailscale
⚠️ Regra de ouro: não faça port forwarding no roteador para portas 80, 443, 22, 3000, 5432 ou 6379. Para uso pessoal, o caminho mais seguro é rede local + Tailscale.
01 / Pré-check
Antes de instalar Ubuntu, valide se o notebook aguenta ficar ligado por longos períodos sem virar uma torradeira.
Antes de formatar, você pode abrir o PowerShell e verificar algumas informações:
systeminfo
wmic diskdrive get model,status,size
wmic memorychip get capacity,speed
wmic cpu get name
💡 Critério prático: se o notebook tiver SSD, 8 GB+ RAM e não superaquecer, ele serve muito bem para Atlas e Ledger como projetos pessoais.
02 / Instalação
Baixe a ISO do Ubuntu Server LTS e grave no pendrive. No Windows, a forma mais simples é usar o Rufus.
⚠️ Atenção: na instalação, você vai escolher o disco do notebook. Confirme duas vezes antes de apagar.
03 / Dell BIOS
Em notebooks Dell, normalmente você usa F12 para abrir o menu de boot e F2 para entrar na BIOS.
| Configuração | Valor sugerido | Por quê |
|---|---|---|
| Boot Mode | UEFI | Mais moderno e recomendado para Ubuntu atual. |
| Secure Boot | Desativar se der erro | Ubuntu costuma funcionar com Secure Boot, mas alguns setups antigos dão dor de cabeça. |
| AC Recovery / Power On AC Attach | Power On | Faz o notebook ligar sozinho quando a energia voltar, se a BIOS suportar. |
| Wake on LAN | Ativar opcionalmente | Permite acordar/ligar pela rede em alguns cenários. |
💡 Nem todo Inspiron tem todas as opções. Se não existir auto power on, ainda dá para usar, só não ligará sozinho após queda total de energia.
04 / Sistema
O Ubuntu Server é mais leve e estável para esse uso do que uma instalação desktop cheia de interface gráfica.
✅ Meta desta fase: notebook ligando direto no Ubuntu Server, com usuário sudo e SSH disponível.
05 / Pós-instalação
Depois de instalar, atualize o sistema, instale ferramentas básicas e confirme o IP atual do servidor.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git unzip htop nano vim ufw ca-certificates gnupg lsb-release apt-transport-https software-properties-common
ip a
Procure algo como:
inet 192.168.0.50/24
No PowerShell do seu PC principal:
ssh willian@192.168.0.50
06 / Rede
O melhor caminho é reservar o IP do notebook no roteador, usando o MAC address. Assim você evita mexer no Netplan do Ubuntu.
192.168.0.50.ip link
Procure a interface cabeada, geralmente enp..., e o campo link/ether.
Use apenas se seu roteador não permitir reserva DHCP.
ls /etc/netplan
sudo nano /etc/netplan/00-installer-config.yaml
Exemplo de configuração. Ajuste interface, gateway e DNS conforme sua rede:
network:
version: 2
ethernets:
enp3s0:
dhcp4: no
addresses:
- 192.168.0.50/24
routes:
- to: default
via: 192.168.0.1
nameservers:
addresses:
- 1.1.1.1
- 8.8.8.8
Aplicar:
sudo netplan try
sudo netplan apply
⚠️ Cuidado: se configurar Netplan errado, você pode perder SSH e precisar corrigir direto no notebook. Por isso a reserva DHCP no roteador é mais segura.
07 / Energia
Notebook como servidor precisa ignorar tampa fechada, não suspender por inatividade e tentar religar quando a energia voltar.
sudo nano /etc/systemd/logind.conf
Altere ou adicione:
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
IdleAction=ignore
Reinicie o serviço:
sudo systemctl restart systemd-logind
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target
Entre na BIOS com F2 e procure por:
AC RecoveryRestore on AC Power LossPower On AC AttachWake on ACConfigure como Power On, se existir.
08 / Runtime
Docker Compose será o centro do setup. Cada aplicação roda em container, e o Caddy roteia os domínios locais para o container certo.
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt remove -y $pkg || true; done
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo ${UBUNTU_CODENAME:-$VERSION_CODENAME}) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world
docker compose version
09 / Proxy
O Caddy será o reverse proxy local. Você acessa atlas.local, e ele encaminha internamente para o container do Atlas.
O mesmo vale para ledger.local.
atlas.local ─┐
├── DNS local → 192.168.0.50 → Caddy → atlas:3000
ledger.local ─┘ └→ ledger:3000
💡 Sobre .local: funciona em muitos ambientes, mas pode conflitar com mDNS/Bonjour. O domínio tecnicamente mais seguro para rede doméstica é .home.arpa. Por isso o guia configura os dois.
sudo mkdir -p /srv/homelab/{proxy,apps,backups,scripts}
sudo chown -R $USER:$USER /srv/homelab
cd /srv/homelab
nano /srv/homelab/proxy/Caddyfile
Conteúdo:
{
auto_https off
}
atlas.local, atlas.home.arpa {
reverse_proxy atlas:3000
}
ledger.local, ledger.home.arpa {
reverse_proxy ledger:3000
}
Abra o Bloco de Notas como Administrador e edite:
C:\Windows\System32\drivers\etc\hosts
Adicione:
192.168.0.50 atlas.local
192.168.0.50 ledger.local
192.168.0.50 atlas.home.arpa
192.168.0.50 ledger.home.arpa
ipconfig /flushdns
Para funcionar no celular, você precisa que o roteador ou um DNS interno resolva esses nomes. As melhores opções são:
| Nome | Tipo | Destino |
|---|---|---|
atlas.local | A | 192.168.0.50 |
ledger.local | A | 192.168.0.50 |
atlas.home.arpa | A | 192.168.0.50 |
ledger.home.arpa | A | 192.168.0.50 |
10 / Acesso remoto
Tailscale cria uma rede privada entre seus dispositivos. Seu celular no 5G não entra literalmente no Wi-Fi da sua casa, mas consegue acessar o notebook como se estivesse numa rede privada compartilhada.
Celular no 5G
↓
App Tailscale conectado
↓
Tailnet privada
↓
Notebook Dell com Tailscale
↓
Atlas / Ledger
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
O comando vai exibir um link. Abra no navegador, faça login e autorize o servidor.
tailscale ip -4
tailscale status
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.0.0/24
sudo ufw allow in on tailscale0
sudo ufw enable
sudo ufw status verbose
No painel do Tailscale, ative MagicDNS. Isso permite acessar dispositivos pelo nome dentro da tailnet. Exemplo:
http://dell-server:80
Para usar exatamente atlas.local no 5G, você precisaria de DNS local acessível pela tailnet ou configurar
Split DNS no Tailscale. Para evitar atrito, o setup mais estável é:
| Cenário | Endereço sugerido |
|---|---|
| PC na rede local | http://atlas.local e http://ledger.local |
| Celular no Wi-Fi com DNS local | http://atlas.local e http://ledger.local |
| Celular no 5G com Tailscale simples | http://IP_TAILSCALE ou http://dell-server |
| Celular no 5G com Split DNS | http://atlas.home.arpa e http://ledger.home.arpa |
✅ Recomendação prática: comece com Tailscale + IP do servidor. Depois refinamos para Split DNS se você quiser uma experiência 100% domínio também no 5G.
11 / Aplicações
A forma mais simples de operar é manter um docker-compose.yml raiz em /srv/homelab com Caddy,
Atlas, Ledger e serviços compartilhados como Postgres e Redis.
/srv/homelab
├── docker-compose.yml
├── .env
├── proxy
│ └── Caddyfile
├── apps
│ ├── atlas
│ └── ledger
├── backups
└── scripts
cd /srv/homelab/apps
git clone git@github.com:SEU_USUARIO/atlas.git atlas
git clone git@github.com:SEU_USUARIO/ledger.git ledger
💡 Se você ainda não usa SSH no GitHub: também pode clonar via HTTPS no começo. Para deploy automático, SSH fica mais confortável depois.
POSTGRES_USER=homelab
POSTGRES_PASSWORD=troque_essa_senha
POSTGRES_DB=homelab
REDIS_PASSWORD=troque_essa_senha_tambem
ATLAS_PORT=3000
LEDGER_PORT=3000
services:
caddy:
image: caddy:2
container_name: homelab-caddy
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./proxy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- atlas
- ledger
networks:
- homelab
atlas:
build:
context: ./apps/atlas
dockerfile: Dockerfile
container_name: atlas
restart: unless-stopped
env_file:
- ./.env
expose:
- "3000"
depends_on:
- postgres
- redis
networks:
- homelab
ledger:
build:
context: ./apps/ledger
dockerfile: Dockerfile
container_name: ledger
restart: unless-stopped
env_file:
- ./.env
expose:
- "3000"
depends_on:
- postgres
- redis
networks:
- homelab
postgres:
image: postgres:16
container_name: homelab-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- homelab
redis:
image: redis:7-alpine
container_name: homelab-redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- homelab
networks:
homelab:
driver: bridge
volumes:
caddy_data:
caddy_config:
postgres_data:
redis_data:
cd /srv/homelab
docker compose up -d --build
docker compose ps
docker compose logs -f caddy
docker compose logs -f atlas
docker compose logs -f ledger
curl -I http://localhost
curl -I -H "Host: atlas.local" http://localhost
curl -I -H "Host: ledger.local" http://localhost
curl -I http://atlas.local
curl -I http://ledger.local
12 / Deploy
A melhor estratégia para seu caso é usar GitHub Actions com self-hosted runner instalado no próprio notebook. Assim o notebook se conecta ao GitHub por saída HTTPS e executa o deploy localmente. Você não abre SSH para a internet.
Você no PC
↓ git push
GitHub
↓ dispara workflow
Self-hosted runner no notebook
↓
git pull / docker compose build / docker compose up -d
↓
Atlas e Ledger atualizados
⚠️ Segurança: use self-hosted runner apenas em repositórios privados ou controlados. Não permita que pull requests de desconhecidos executem código no seu notebook.
sudo apt install -y libicu-dev jq
sudo adduser github-runner
sudo usermod -aG docker github-runner
Depois de configurar o runner, entre na pasta do runner e rode:
sudo ./svc.sh install github-runner
sudo ./svc.sh start
sudo ./svc.sh status
Crie:
nano /srv/homelab/scripts/deploy.sh
Conteúdo:
#!/usr/bin/env bash
set -euo pipefail
cd /srv/homelab
echo "[deploy] Atualizando Atlas..."
cd /srv/homelab/apps/atlas
git fetch origin
git reset --hard origin/main
echo "[deploy] Atualizando Ledger..."
cd /srv/homelab/apps/ledger
git fetch origin
git reset --hard origin/main
echo "[deploy] Rebuild e restart..."
cd /srv/homelab
docker compose up -d --build
echo "[deploy] Limpando imagens antigas..."
docker image prune -f
echo "[deploy] Status final:"
docker compose ps
Permissão:
chmod +x /srv/homelab/scripts/deploy.sh
No repo do Atlas, crie .github/workflows/deploy-local.yml:
name: Deploy Atlas Local
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: self-hosted
steps:
- name: Deploy no servidor local
run: /srv/homelab/scripts/deploy.sh
No repo do Ledger, crie o mesmo arquivo:
name: Deploy Ledger Local
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: self-hosted
steps:
- name: Deploy no servidor local
run: /srv/homelab/scripts/deploy.sh
💡 Por que o script atualiza os dois projetos? Porque você terá um compose único em /srv/homelab. Quando fizer push no Atlas ou no Ledger, o servidor sincroniza os dois e sobe o stack inteiro. É simples e robusto para uso pessoal.
Depois, se quiser, você pode separar em:
deploy-atlas.sh
deploy-ledger.sh
docker compose up -d --build atlas
docker compose up -d --build ledger
13 / Backup
Notebook antigo pode morrer sem avisar. Mesmo sendo projeto pessoal, faça backup do banco e dos volumes.
Crie:
nano /srv/homelab/scripts/backup-postgres.sh
Conteúdo:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/srv/homelab/backups/postgres"
DATE="$(date +%Y-%m-%d_%H-%M-%S)"
mkdir -p "$BACKUP_DIR"
cd /srv/homelab
docker compose exec -T postgres pg_dumpall -U "$POSTGRES_USER" > "$BACKUP_DIR/postgres_$DATE.sql"
gzip "$BACKUP_DIR/postgres_$DATE.sql"
find "$BACKUP_DIR" -type f -name "*.gz" -mtime +14 -delete
echo "Backup criado em $BACKUP_DIR/postgres_$DATE.sql.gz"
Permissão:
chmod +x /srv/homelab/scripts/backup-postgres.sh
crontab -e
Adicionar backup diário às 03:00:
0 3 * * * /srv/homelab/scripts/backup-postgres.sh >> /srv/homelab/backups/backup.log 2>&1
Além do backup local, copie periodicamente para:
HD externo;
Google Drive/OneDrive via rclone;
outro PC da rede;
VPS;
NAS.
14 / Operação
Você precisa saber se os containers estão vivos, se o servidor esquentou demais e se o disco está saudável.
sudo apt install -y lm-sensors
sudo sensors-detect
sensors
df -h
docker system df
htop
No docker-compose.yml, adicione:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
volumes:
- uptime_kuma_data:/app/data
expose:
- "3001"
networks:
- homelab
No final dos volumes:
uptime_kuma_data:
No Caddyfile:
kuma.local, kuma.home.arpa {
reverse_proxy uptime-kuma:3001
}
15 / Segurança
Para seu caso, a melhor segurança é simples: não abrir porta no roteador, usar firewall e acessar remotamente só via Tailscale.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.0.0/24
sudo ufw allow in on tailscale0
sudo ufw enable
sudo ufw status verbose
Com a regra acima, SSH será acessível apenas pela rede local ou Tailscale, desde que não exista port forwarding no roteador.
No compose, prefira expose em vez de ports para Postgres e Redis. Assim eles ficam acessíveis só entre containers.
sudo apt update && sudo apt upgrade -y
docker compose pull
docker compose up -d
docker image prune -f
16 / Problemas comuns
http://192.168.0.50.ping atlas.local.ipconfig /flushdns.curl -I -H "Host: atlas.local" http://localhost.docker compose logs -f caddy.cd /srv/homelab
docker compose config
docker compose logs -f
docker compose ps
sudo ./svc.sh status
journalctl -u actions.runner* -f
tailscale status
tailscale netcheck
sudo systemctl status tailscaled
grep -E "HandleLidSwitch|IdleAction" /etc/systemd/logind.conf
systemctl status systemd-logind
systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target
cd /srv/homelab
docker compose down
docker compose up -d --build
docker compose ps
17 / Final
Quando todos esses itens estiverem marcados, seu servidor local estará pronto para uso real no dia a dia.
✅ Resultado final: Atlas e Ledger rodando em servidor local privado, com acesso bonito por domínio, acesso remoto seguro via Tailscale e deploy por commit sem expor sua rede.
Refs / Fontes oficiais
Referências
Ubuntu Server — guia oficial de instalação: ubuntu.com/tutorials/install-ubuntu-server
Ubuntu — criar pendrive bootável: ubuntu.com/tutorials/create-a-usb-stick-on-ubuntu
Docker Engine no Ubuntu — documentação oficial: docs.docker.com/engine/install/ubuntu
Caddy reverse proxy — documentação oficial: caddyserver.com/docs/quick-starts/reverse-proxy
Tailscale Linux — documentação oficial: tailscale.com/docs/install/linux
GitHub self-hosted runners — documentação oficial: docs.github.com/actions/hosting-your-own-runners/adding-self-hosted-runners
GitHub runner como serviço — documentação oficial: docs.github.com/actions/hosting-your-own-runners/managing-self-hosted-runners/configuring-the-self-hosted-runner-application-as-a-service
RFC 8375 — domínio especial home.arpa: datatracker.ietf.org/doc/html/rfc8375
Dark n Black / Local Server Runbook / v2 brutalista / checklist salvo no navegador via localStorage.