This repository manages a homelab using GitOps practices with Docker Swarm.
- Keep infrastructure as code, versioned in Git.
- Start with core services: AdGuard Home (DNS/DHCP) and Nginx.
- Use
.arpalocal domains with the pattern<app>.arpa, whereappis a placeholder for the service name. - HTTPS em todos os serviços via CA interna e certificado wildcard
*.arpa. - Scale by adding new stacks and configurations over time.
.
|-- certs/ # Certificados TLS (não versionado — gerado localmente)
| |-- ca/ # Root CA (distribuir ca.crt para dispositivos)
| |-- wildcard.arpa.* # Certificado wildcard *.arpa
| `-- dhparam.pem # Parâmetros DH para Forward Secrecy
|-- configs/
| |-- adguard/
| | `-- AdGuardHome.yaml
| `-- nginx/
| |-- apps.wildcard.arpa.conf
| `-- default.conf
|-- scripts/
| |-- deploy.sh
| |-- generate-certs.sh # Gerar CA interna + wildcard *.arpa
| |-- update.sh # Atualizar imagens e reimplantar stacks
| `-- remove.sh
`-- stacks/
`-- core/
|-- .env.example
`-- docker-stack.yml
- Docker Engine in Swarm mode (
docker swarm initon the manager) - A manager node where the stack can run
- OpenSSL (para gerar certificados)
-
Copiar template de ambiente se necessário:
cp stacks/core/.env.example stacks/core/.env
-
Gerar certificados TLS (CA interna + wildcard
*.arpa):./scripts/generate-certs.sh
-
Distribuir o certificado da CA para os dispositivos da rede (veja Internal CA & TLS).
-
Subir o stack:
./scripts/deploy.sh core
-
Verificar serviços:
docker stack services core
-
Acessar:
https://adguard.arpa -
Remover o stack:
./scripts/remove.sh core
O homelab opera com uma CA (Certificate Authority) interna que assina um certificado wildcard *.arpa. Isso elimina avisos de "inseguro" em todos os navegadores, desde que o certificado da CA esteja instalado no dispositivo.
graph TD
subgraph "Rede Local"
D1[Notebook]
D2[Desktop]
D3[Smartphone]
end
D1 & D2 & D3 -->|"HTTPS *.arpa"| NGINX
subgraph "Docker Swarm — Manager Node"
NGINX[Nginx :443<br/>TLS Termination<br/>HTTP/2]
subgraph "Serviços"
AG[AdGuard Home<br/>:8080]
APP1[Portainer<br/>:80]
APP2[Grafana<br/>:80]
APPn[...]
end
NGINX -->|"adguard.arpa → host:8080"| AG
NGINX -->|"portainer.arpa → overlay:80"| APP1
NGINX -->|"grafana.arpa → overlay:80"| APP2
NGINX -->|"*.arpa → overlay:80"| APPn
end
CA[Root CA<br/>Homelab Internal CA] -.->|"Assina wildcard<br/>*.arpa + arpa"| NGINX
sequenceDiagram
participant Browser as 🌐 Navegador
participant DNS as 📡 AdGuard DNS
participant Nginx as 🔒 Nginx :443
participant App as 📦 App Container
Browser->>DNS: Resolver adguard.arpa
DNS-->>Browser: 192.168.1.113
Browser->>Nginx: TLS Handshake (SNI: adguard.arpa)
Nginx-->>Browser: Cert wildcard *.arpa
Browser->>Browser: ✅ Valida contra CA interna
Browser->>Nginx: GET / (HTTPS)
Nginx->>App: proxy_pass http://adguard:80
App-->>Nginx: 200 OK
Nginx-->>Browser: 200 OK (HTTPS)
./scripts/generate-certs.shIsso cria:
| Arquivo | Propósito |
|---|---|
certs/ca/ca.crt |
Certificado da CA — instalar nos dispositivos |
certs/ca/ca.key |
Chave privada da CA — manter em segredo |
certs/wildcard.arpa.crt |
Certificado wildcard assinado |
certs/wildcard.arpa.key |
Chave privada do wildcard |
certs/wildcard.arpa.fullchain.pem |
Cadeia completa (cert + CA) para Nginx |
certs/dhparam.pem |
Parâmetros Diffie-Hellman para Forward Secrecy |
Linux (sistema):
sudo cp certs/ca/ca.crt /usr/local/share/ca-certificates/homelab-ca.crt
sudo update-ca-certificatesLinux (Firefox — trust store próprio): Preferences → Privacy & Security → View Certificates → Authorities → Import
Windows:
Duplo clique em ca.crt → Instalar → Trusted Root Certification Authorities
macOS:
Duplo clique em ca.crt → Keychain → System → Always Trust
Android: Settings → Security → Encryption & Credentials → Install from storage
iOS:
Abrir ca.crt no Safari → Profile Downloaded → Settings → Install
Os certificados wildcard expiram em 5 anos. Para renovar, basta rodar novamente:
./scripts/generate-certs.sh # sobrescreve os certs antigos
./scripts/deploy.sh core # recarrega o Nginx com os novos certs
⚠️ O diretóriocerts/contém chaves privadas e não deve ser versionado no Git. O.gitignorejá o exclui.
Os serviços usam tags flutuantes (latest, alpine, etc.) para que possam ser
atualizados de forma simples. Para atualizar todas as imagens e reimplantar os stacks:
./scripts/update.sh # todos os stacks em stacks/
./scripts/update.sh core # apenas o stack "core"O script faz, para cada stack:
docker pulldas imagens definidas nodocker-stack.yml;- reimplanta o stack via
./scripts/deploy.sh <stack>.
Como o docker stack deploy resolve as tags a cada execução
(--resolve-image always), os serviços são recriados com a imagem mais recente.
Para fixar uma versão específica, troque a tag no
docker-stack.yml(ex.:nginx:alpine→nginx:1.30.5-alpine). O script continuará funcionando, mas só atualizará quando a tag apontada mudar.
- AdGuard is configured as a single replica and pinned to a manager node by default.
- DHCP in containers can require network and host-level adjustments depending on your LAN setup.
- The setup wizard is exposed on
https://<node-ip>:3000. - AdGuard main UI is exposed on
https://<node-ip>:8080and proxied by Nginx athttps://adguard.arpa. - Use local domains under
.arpa(pattern:<app>.arpa), and avoid.home. - Add future stacks under
stacks/<name>/docker-stack.ymland deploy with the same script. - O Nginx faz redirect automático HTTP → HTTPS em todos os domínios
*.arpa. - OCSP Stapling está desabilitado (CA interna não tem responder OCSP público).
Recommended pattern:
<app>.arpa
app is a variable, not a fixed middle label. That means the expected hostnames are adguard.arpa, portainer.arpa, and grafana.arpa instead of adguard.app.arpa.
Examples:
adguard.arpaportainer.arpagrafana.arpa
Inside AdGuard DNS, create A records for these names pointing to the Swarm manager IP.
Nginx wildcard routing uses the left-most label as the upstream service name.
For example, adguard.arpa proxies to service adguard on port 80.
- Keep DHCP on the router for now and use AdGuard only as DNS.
- Set router DNS to the AdGuard host IP.
- Validate local records and DNS filtering behavior.
- Schedule a migration window.
- Disable router DHCP.
- Enable DHCP in AdGuard with the same gateway/subnet and a safe IP range.
- Reboot or renew leases on clients.
Only one DHCP server must be active on the LAN at a time.