Esse parece ser um tópico um tanto quanto... distópico? Talvez nem tanto. Mas todas as referências sobre o assunto na Internet estão incompletos e geralmente são pra versões mais antigas do traefik. Traefik é um roteador de conexões que funciona tanto como programa chamado por systemd (ou outro sistema de init se for um BSD), ou por container com algo como docker-compose, ou ainda diretamente em kubernetes. E não só funciona como proxy-reverse: pode também atuar como um servidor http pra suas conexões. E não somente tcp como udp. E escrito em Go!
Eu precisei colocar um servidor ssh atrás de um traefik. E deu um certo trabalho. Pra testar e mostrar aqui também, usei docker-compose pro serviço. Isso facilitou a configuração. Pra backend com ssh, subi uma instância do gitea com o ssh na porta 2222. Usei também certificados letsencrypt nas portas https do serviço.
Como um plus, ainda adicionei um allowlist pra acessar o serviço somente de certos IPs.
Vamos pra configuração então. Primeiramente do traefik.
Pra subir, eu configurei pra ouvir nas portas 80 (http), 443 (https), 8080 (traefik dashboard) e 2222 (ssh).
O conteúdo de traefik/docker-compose.yml
:
services:
traefik:
image: "traefik:v3.3"
container_name: "traefik"
restart: unless-stopped
environment:
- TZ=Europe/Stockholm
ports:
- "80:80"
- "443:443"
- "8080:8080"
- "2222:2222"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik.yml:/traefik.yml:ro"
networks:
- traefik
networks:
traefik:
name: traefik
Junto com essa configuração de container, ainda inclui a configuração do serviço em traefik/traefik.yml
:
api:
dashboard: true
insecure: true
debug: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
ssh:
address: ":2222"
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik
certificatesResolvers:
letsencrypt:
acme:
email: This email address is being protected from spambots. You need JavaScript enabled to view it.
storage: /letsencrypt/acme.json
httpChallenge:
# used during the challenge
entryPoint: web
log:
level: WARN
Aqui é possível ver que defino novamente os entrypoints pra 80, 443 e 2222. E no 80 (http) eu redireciono pro 443 (https). E certificado do letsencrypt.
Tudo pronto no lado do traefik. Agora é o ponto de subir o serviço e preparar algumas coisas pra testar.
# docker compose -p traefik -f traefik/docker-compose.yml up -d
[+] Running 1/1
✔ Container traefik Started 0.4s
Dentro do diretório traefik
será criado um diretório letsencrypt
e dentro dele terá o arquivo acme.json
com seus certificados.
Primeiramente vamos subir um container de teste pra ver se tudo funciona.
O próprio projeto traefik fornece um container chamado whoami pra isso.
O conteúdo de whois/docker-compose.yml
:
services:
whoami:
container_name: simple-service
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.tests.loureiro.eng.br`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls=true"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
- traefik
networks:
traefik:
name: traefik
E habilitando o serviço com docker-compose
:
# docker compose -p whoami -f whoami/docker-compose.yml up -d
WARN[0000] a network with name traefik exists but was not created for project "whoami".
Set `external: true` to use an existing network
[+] Running 1/1
✔ Container simple-service Started 0.3s
E um simples teste do serviço:
❯ curl -I http://whoami.tests.loureiro.eng.br
HTTP/1.1 308 Permanent Redirect
Location: https://whoami.tests.loureiro.eng.br/
Date: Thu, 24 Apr 2025 12:43:55 GMT
Content-Length: 18
❯ curl https://whoami.tests.loureiro.eng.br
Hostname: 0da540e1039c
IP: 127.0.0.1
IP: ::1
IP: 172.18.0.3
RemoteAddr: 172.18.0.2:52686
GET / HTTP/1.1
Host: whoami.tests.loureiro.eng.br
User-Agent: curl/8.5.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 1.2.3.4
X-Forwarded-Host: whoami.tests.loureiro.eng.br
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 4cacedb0129a
X-Real-Ip: 1.2.3.4
O primeiro curl
pro endpoint na porta 80 (http) recebe um redirect pra https.
Perfeito!
O segundo, os dados do container de forma transparente.
O serviço funciona! Mas pra http e https. Falta ssh na porta 2222, que está nessa porta pra não atrapalhar o uso do ssh normal do sistema.
Pra isso eu configurei um gitea, como descrevi no início do artigo.
Seu docker-compose.yml
é o seguinte:
services:
server:
image: gitea/gitea:1.23-rootless #latest-rootless
container_name: gitea
environment:
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=A4COU5a6JF5ZvWoSufi0L1aomSkzqww7s1wv039qy6o=
- LOCAL_ROOT_URL=https://gitea.tests.loureiro.eng.br
- GITEA__openid__ENABLE_OPENID_SIGNIN=false
- GITEA__openid__ENABLE_OPENID_SIGNUP=false
- GITEA__service__DISABLE_REGISTRATION=true
- GITEA__service__SHOW_REGISTRATION_BUTTON=false
- GITEA__server__SSH_DOMAIN=gitea.tests.loureiro.eng.br
- GITEA__server__START_SSH_SERVER=true
- GITEA__server__DISABLE_SSH=false
restart: always
volumes:
- gitea-data:/var/lib/gitea
- gitea-config:/etc/gitea
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
#ports:
# - "127.0.0.1:3000:3000"
# - "127.0.0.1:2222:2222"
depends_on:
- db
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.giteaweb.rule=Host(`gitea.tests.loureiro.eng.br`)"
- "traefik.http.routers.giteaweb.entrypoints=websecure"
- "traefik.http.routers.giteaweb.tls=true"
- "traefik.http.routers.giteaweb.tls.certresolver=letsencrypt"
- "traefik.http.services.giteaweb.loadbalancer.server.port=3000"
- "traefik.http.middlewares.giteaweb-ipwhitelist.ipallowlist.sourcerange=1.2.3.4, 4.5.6.7"
- "traefik.http.routers.giteaweb.middlewares=giteaweb-ipwhitelist"
- "traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`)"
- "traefik.tcp.routers.gitea-ssh.entrypoints=ssh"
- "traefik.tcp.routers.gitea-ssh.service=gitea-ssh-svc"
- "traefik.tcp.services.gitea-ssh-svc.loadbalancer.server.port=2222"
- "traefik.tcp.middlewares.giteassh-ipwhitelist.ipallowlist.sourcerange=1.2.3.4, 4.5.6.7"
- "traefik.tcp.routers.gitea-ssh.middlewares=giteassh-ipwhitelist"
db:
image: postgres:17
restart: always
container_name: gitea_db
environment:
- POSTGRES_DB=gitea
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=A4COU5a6JF5ZvWoSufi0L1aomSkzqww7s1wv039qy6o=
networks:
- traefik
volumes:
- gitea-db:/var/lib/postgresql/data
networks:
traefik:
name: traefik
volumes:
gitea-data:
gitea-config:
gitea-db:
Pode ser visto que existe uma regra pra parte web, que roda na porta 3000 do container, e pra parte de ssh, que fica na porta 22222. Eu deixei comentado a parte que exporta as portas pra mostrar claramente que isso não é necessário. Aliás não funciona se especificar as portas.
E finalmente rodando o serviço:
# docker compose -p gitea -f gitea/docker-compose.yml up -d
WARN[0000] a network with name traefik exists but was not created for project "gitea".
Set `external: true` to use an existing network
[+] Running 2/2
✔ Container gitea_db Started 0.3s
✔ Container gitea Started 1.0s
E vamos ao testes.
❯ curl -s https://gitea.tests.loureiro.eng.br | head -n 10
<!DOCTYPE html>
<html lang="en-US" data-theme="gitea-auto">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Gitea: Git with a cup of tea</title>
<link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwLyIsImljb25zIjpbeyJzcmMiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmciLCJzaXplcyI6IjUxMng1MTIifSx7InNyYyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9hc3NldHMvaW1nL2xvZ28uc3ZnIiwidHlwZSI6ImltYWdlL3N2Zyt4bWwiLCJzaXplcyI6IjUxMng1MTIifV19">
<meta name="author" content="Gitea - Git with a cup of tea">
<meta name="description" content="Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go">
<meta name="keywords" content="go,git,self-hosted,gitea">
<meta name="referrer" content="no-referrer">
❯ telnet gitea.tests.loureiro.eng.br 2222
Trying 1.2.3.4...
Connected to gitea.tests.loureiro.eng.br.
Escape character is '^]'.
SSH-2.0-Go
^]
telnet> q
Connection closed.
E pronto! Temos o serviço funcionando e roteado pelo traefik. E podendo fazer ACL de ip do serviço sem precisar do firewall pra isso.
Boa diversão!
Nota: eu coloquei um básico da configuração do gitea pra exemplo. E não funciona se copiar e colar. Pra ter um serviço rodando, terá de adicionar mais algumas partes em environment.
We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.