melhorias de docker

This commit is contained in:
Luiz Silva 2025-12-31 11:56:10 -03:00
parent 31499a0c69
commit 67d4e86302
3 changed files with 80 additions and 0 deletions

26
Caddyfile Normal file
View file

@ -0,0 +1,26 @@
# Caddyfile
#
# Objetivo:
# - Publicar o serviço e-li.nps em https://nps.idz.one
# - Fazer reverse proxy para o backend em {ip-app}:8080
# - Preservar IP real do cliente para a aplicação (X-Forwarded-For / X-Real-IP)
#
# Observações importantes:
# - TLS automático requer que o DNS de nps.idz.one aponte para o IP público do Caddy
# e que as portas 80/443 estejam liberadas.
# - O IP real chegará na aplicação via X-Forwarded-For, que é interpretado pelo
# middleware.RealIP do chi (já habilitado no projeto).
nps.idz.one {
encode gzip
# Reverse proxy para o backend
reverse_proxy {ip-app}:8080 {
# Cabeçalhos padrão para preservar IP e esquema
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
}
}

View file

@ -117,6 +117,45 @@ DATABASE_URL='postgres://usuario:senha@host.docker.internal:5432/seu_banco?sslmo
No Linux, o `docker-compose.yml` já inclui `extra_hosts` com `host-gateway` para No Linux, o `docker-compose.yml` já inclui `extra_hosts` com `host-gateway` para
esse hostname funcionar. esse hostname funcionar.
## Publicar com Caddy (reverse proxy)
Este repositório inclui um exemplo de `Caddyfile` para publicar o serviço em:
- `https://nps.idz.one``{ip-app}:8080`
### Pré-requisitos
- O DNS de `nps.idz.one` deve apontar para o **IP público** do servidor onde o Caddy roda.
- Portas **80/443** liberadas para o Caddy (TLS automático).
### IP real do usuário
O Caddy repassa o IP do cliente via `X-Forwarded-For` e `X-Real-IP`.
O servidor Go já usa `middleware.RealIP` (chi), então o IP real chega corretamente
e é gravado em `ip_real`.
### Check do IP real (direto / Docker / Caddy)
O painel tem um endpoint de debug que mostra o IP que a aplicação está enxergando
e os headers recebidos:
- `GET /painel/debug/ip`
Passo a passo:
1) Faça login no painel em `/painel`.
2) Acesse `/painel/debug/ip`.
O JSON retornado inclui:
- `remote_addr` (já após o `middleware.RealIP`)
- `x_forwarded_for`
- `x_real_ip`
Interpretação esperada:
- Rodando **direto** (sem proxy): `remote_addr` deve ser o IP do cliente (ou do seu balanceador).
- Rodando via **Docker**: se você acessar diretamente a porta publicada, o `remote_addr` tende a ser o IP do host/bridge; atrás de proxy (Caddy), o `remote_addr` deve refletir o IP real.
- Rodando via **Caddy**: `x_forwarded_for` deve conter o IP real do cliente e o `remote_addr` deve refletir esse IP após `RealIP`.
Depois acesse: Depois acesse:
- Home/README: `http://localhost:8080/` - Home/README: `http://localhost:8080/`
- Teste do widget: `http://localhost:8080/teste.html` - Teste do widget: `http://localhost:8080/teste.html`

View file

@ -3,6 +3,7 @@ package elinps
import ( import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"encoding/json"
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@ -39,6 +40,20 @@ func (p *PainelHandlers) Router() http.Handler {
p.auth.handlerPainel(w, r, p.store) p.auth.handlerPainel(w, r, p.store)
}) })
// Debug: conferir IP real / headers.
// Protegido pelo mesmo middleware do painel.
r.With(func(next http.Handler) http.Handler { return p.auth.middleware(next) }).Get("/debug/ip", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"remote_addr": r.RemoteAddr,
"x_forwarded_for": r.Header.Get("X-Forwarded-For"),
"x_real_ip": r.Header.Get("X-Real-IP"),
"x_forwarded_proto": r.Header.Get("X-Forwarded-Proto"),
"x_forwarded_host": r.Header.Get("X-Forwarded-Host"),
"user_agent": r.UserAgent(),
})
})
return r return r
} }