Tutoriais de VPS
Implantar Keycloak SSO em um VPS (2026): Docker, PostgreSQL, Caddy HTTPS, OIDC e backups
Implante o Keycloak 26.7.2, PostgreSQL 17 e Caddy HTTPS em um VPS Ubuntu com Docker Compose, configure realms, OIDC, MFA, funções, backups e atualizações seguras, e crie um ponto de entrada de login único auto-hospedado para sua equipe.

Muitas equipes já têm GitLab, Grafana, Jenkins, painéis administrativos internos e aplicações de IA auto-hospedadas, mas ainda criam contas separadas em cada sistema. Quando um funcionário sai, cada conta precisa ser desativada uma a uma, as políticas de senha são diferentes em cada lugar e a auditoria unificada é difícil. O valor do Keycloak não é adicionar mais uma página de login, mas centralizar contas, login único, MFA, funções e políticas de sessão para que aplicações compatíveis com OpenID Connect (OIDC) ou SAML compartilhem um único ponto de entrada de identidade.
Este artigo usa Keycloak 26.7.2, PostgreSQL 17, Docker Compose, Caddy e Ubuntu 24.04 como base para montar em um único VPS um serviço SSO adequado a pequenos ambientes de produção, e demonstra por completo HTTPS com domínio, tratamento do administrador temporário, realms, clientes OIDC, URIs de redirecionamento, funções, backups, atualizações e solução de problemas. A versão do Keycloak e a matriz de suporte oficial foram verificadas em setembro de 2026; antes de implantar de fato, ainda vale conferir os avisos de segurança e as notas de versão mais recentes.
O Keycloak é um sistema de gestão de identidade e acesso, não um gerenciador de senhas comum. Ele pode oferecer login unificado para várias aplicações e cuidar de forma centralizada de:
- autenticação OpenID Connect, OAuth 2.0 e SAML 2.0;
- usuários, grupos, funções de realm, funções de cliente e gestão de atributos;
- TOTP, WebAuthn, políticas de senha, detecção de força bruta e controle de sessão;
- integração com fontes de identidade externas como LDAP, Active Directory, GitHub e Google;
- autoatendimento do usuário para editar perfil, redefinir senha e gerenciar o segundo fator;
- eventos administrativos, eventos de login e permissões de administrador granulares.
Se você só quer adicionar uma barreira de login a uma página web que não suporta OIDC, o Authelia ou o Basic Auth no proxy reverso costuma ser mais leve. Se a própria aplicação suporta OIDC e você precisa de ciclo de vida de usuário unificado, permissões organizacionais ou integrar mais sistemas no futuro, o Keycloak oferece mais espaço para crescer.
| Opção | Vantagens | Principais custos | Mais adequada para |
|---|---|---|---|
| Keycloak | OIDC/SAML completos, realms, funções, fontes de identidade e políticas ricos | Muitas opções de configuração, o serviço Java precisa de limites de memória explícitos | Várias aplicações, contas de equipe, integração de identidade corporativa |
| Authentik | Interface administrativa amigável, recursos completos de proxy e diretório | Também tem muitos componentes e conceitos | Equipes que querem orquestrar o login com fluxos visuais |
| Authelia | Leve, bom para proteger páginas web atrás de um proxy reverso | Não é uma plataforma de identidade corporativa completa | Poucas páginas internas que precisam de autenticação prévia unificada |
| Cada aplicação gerencia suas contas | Início mais rápido | Desligamento de contas, MFA, auditoria e políticas de senha dispersos | Apenas uma aplicação com pouquíssimos usuários |
Este artigo usa uma arquitetura de nó único:
浏览器 / 应用
|
| HTTPS :443
v
Caddy
|
| HTTP 127.0.0.1:8080
v
Keycloak 26.7.2
|
| Docker 内部网络 :5432
v
PostgreSQL 17
健康检查:仅本机访问 127.0.0.1:9000
O Caddy encerra o TLS no VPS, e o Keycloak serve HTTP apenas pelo endereço de loopback. O PostgreSQL não mapeia nenhuma porta do host. O 9000 da interface de administração do Keycloak se liga apenas a 127.0.0.1, não fica atrás do Caddy e não é exposto à internet pública.
O contêiner oficial do Keycloak calcula o heap da JVM com base no limite de memória do contêiner: o heap máximo é, por padrão, cerca de 70% do limite, além da sobrecarga de memória não-heap. A recomendação oficial para pequenas implantações de produção é um limite de memória de contêiner de 2 GB. Considerando PostgreSQL, Caddy, cache do sistema e tarefas de backup, comece pelas seguintes configurações:
| Escala de uso | Ponto de partida sugerido do VPS | Observações |
|---|---|---|
| Testes, menos de 20 usuários | 2 vCPU, 4 GB de RAM, 40 GB NVMe | Não é garantia de disponibilidade, não recomendado para logins críticos |
| Equipe pequena, centenas de usuários, baixa concorrência | 4 vCPU, 8 GB de RAM, 80 GB NVMe | Keycloak limitado a 2 GB, deixando folga ampla para banco de dados e sistema |
| Picos de login evidentes ou muitas fontes de identidade | Faça teste de carga primeiro, depois escale ou passe para vários nós | Hash de senha, diretórios externos e plugins personalizados afetam a capacidade |
Um único VPS continua sendo um ponto único de falha. Enquanto todas as aplicações dependerem dele para login, a indisponibilidade do Keycloak afetará novas sessões. Atividades críticas devem usar um PostgreSQL externo, pelo menos dois nós do Keycloak, balanceamento de carga e backups em outra máquina; não confunda a configuração de nó único deste artigo com uma arquitetura de alta disponibilidade.
Use um domínio dedicado para SSO, por exemplo sso.example.com. Adicione um registro A no provedor de DNS apontando para o endereço público do VPS; adicione um registro AAAA apenas se o VPS realmente tiver IPv6 funcional configurado.
Pouquíssimas portas são necessárias:
| Porta | Origem | Uso | Pública |
|---|---|---|---|
22/TCP | IP de administração | SSH | Melhor restringir por origem |
80/TCP | Pública | Validação de certificado do Caddy e redirecionamento HTTP | Sim |
443/TCP | Pública ou rede especificada | Login do Keycloak e endpoints OIDC/SAML | Sim |
8080/TCP | Host do Caddy | HTTP do Keycloak | Não, apenas loopback |
9000/TCP | Monitoramento local | Verificações de saúde e métricas | Não, apenas loopback |
5432/TCP | Rede interna do Docker | PostgreSQL | Não, não mapeada |
Se o grupo de segurança da nuvem já libera o tráfego mas o acesso ainda falha, verifique camada por camada seguindo o guia de solução de problemas de portas, firewall, grupos de segurança e endereços de escuta; não desative o firewall simplesmente para verificar.
Os comandos a seguir usam Ubuntu 24.04 como exemplo. O Docker deve ser instalado a partir do repositório oficial; se o VPS já executa Docker, não execute novamente scripts de terceiros que sobrescreveriam a configuração do repositório.
sudo apt update
sudo apt full-upgrade -y
sudo apt install -y ca-certificates curl openssl caddy jq
docker --version
docker compose version
sudo systemctl enable --now caddy
Primeiro confirme que docker compose é o Compose v2. Ambientes de produção também devem configurar rotação de logs, limites de recursos, verificações de saúde e um processo de reversão; você pode seguir junto a lista de verificação de configuração de produção do Docker Compose.
Crie um diretório acessível apenas por administradores:
sudo install -d -m 750 -o "$USER" -g "$USER" /opt/keycloak
cd /opt/keycloak
umask 077
Gere a senha do banco de dados e a senha do administrador temporário. Aqui são usados caracteres hexadecimais para evitar que caracteres como $ sejam expandidos novamente pelo Compose como variáveis:
POSTGRES_PASSWORD_VALUE="$(openssl rand -hex 32)"
BOOTSTRAP_PASSWORD_VALUE="$(openssl rand -hex 32)"
cat > .env <<EOF
KC_HOSTNAME=sso.example.com
POSTGRES_DB=keycloak
POSTGRES_USER=keycloak
POSTGRES_PASSWORD=${POSTGRES_PASSWORD_VALUE}
KC_BOOTSTRAP_ADMIN_USERNAME=temp-admin
KC_BOOTSTRAP_ADMIN_PASSWORD=${BOOTSTRAP_PASSWORD_VALUE}
EOF
chmod 600 .env
unset POSTGRES_PASSWORD_VALUE BOOTSTRAP_PASSWORD_VALUE
Substitua sso.example.com pelo seu domínio real. Não faça commit de .env no Git, nem cole em chats, capturas de tela ou tickets. O Keycloak também suporta oficialmente armazenar configurações sensíveis em um Java KeyStore; este artigo usa um arquivo de ambiente com permissões restritas para tornar os passos de implantação em uma única máquina mais fáceis de reproduzir.
Ao confirmar as permissões de arquivo e o resultado da expansão do Compose, não exiba senhas reais diretamente:
stat -c '%a %U:%G %n' .env
grep -E '^(KC_HOSTNAME|POSTGRES_DB|POSTGRES_USER|KC_BOOTSTRAP_ADMIN_USERNAME)=' .env
O Keycloak recomenda oficialmente executar primeiro build e depois iniciar com start --optimized. Assim, opções de tempo de build como drivers de banco de dados, verificações de saúde e métricas são gravadas antecipadamente na imagem, e a inicialização não precisa repetir a detecção e a construção.
Crie /opt/keycloak/Containerfile:
FROM quay.io/keycloak/keycloak:26.7.2 AS builder
ENV KC_DB=postgres
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:26.7.2
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
Não use latest em produção. Este artigo fixa o Keycloak 26.7.2; ao atualizar, altere os dois FROM, reconstrua e conclua o backup do banco de dados e os testes de reversão.
Crie /opt/keycloak/compose.yaml:
services:
postgres:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 10
start_period: 20s
networks:
- keycloak_internal
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
keycloak:
build:
context: .
dockerfile: Containerfile
image: local/keycloak:26.7.2
restart: unless-stopped
command: ["start", "--optimized"]
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
KC_DB_USERNAME: ${POSTGRES_USER}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
KC_HOSTNAME: https://${KC_HOSTNAME}
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD}
depends_on:
postgres:
condition: service_healthy
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:9000:9000"
mem_limit: 2g
cpus: 2.0
healthcheck:
test:
- CMD-SHELL
- "{ printf 'HEAD /health/ready HTTP/1.0\r\n\r\n' >&0; grep 'HTTP/1.0 200'; } 0<>/dev/tcp/localhost/9000"
interval: 30s
timeout: 5s
retries: 10
start_period: 60s
networks:
- keycloak_internal
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
networks:
keycloak_internal:
driver: bridge
volumes:
postgres_data:
Há vários pontos-chave aqui:
- O PostgreSQL 17 está dentro da faixa PostgreSQL 14–18 oficialmente suportada pelo Keycloak 26.7.2;
- O banco de dados não tem
portse só pode ser acessado pelo Keycloak na rede interna; KC_HTTP_ENABLED=truepermite apenas que Caddy e Keycloak se comuniquem em texto simples na máquina local; a internet pública continua usando HTTPS;KC_HOSTNAMEé escrito como URL externa completa para evitar erros no emissor, no redirecionamento e nos endereços de recursos estáticos;KC_PROXY_HEADERS=xforwardedpermite que o Keycloak analise oX-Forwarded-*definido pelo Caddy;9000se liga apenas ao endereço de loopback para verificações do host, sem exposição pelo Caddy;- O Keycloak é configurado com limite de memória de 2 GB para evitar que a JVM expanda o heap com base na memória de todo o host.
Se o limite de 2 GB causar pressão de memória em outros serviços da mesma máquina, não o reduza simplesmente para algumas centenas de MB e finja que está pronto para produção. Migre outros serviços, adicione memória ao VPS ou execute primeiro testes de carga reais.
Primeiro renderize a configuração do Compose. O resultado renderizado contém informações sensíveis, então use-o apenas para verificações locais e exclua-o imediatamente após visualizar:
cd /opt/keycloak
docker compose config --quiet
docker compose build --pull keycloak
docker compose up -d
docker compose ps
A primeira inicialização inicializa o banco de dados e o realm master, e costuma ser mais lenta que as seguintes. Acompanhe os logs continuamente:
docker compose logs -f --tail=200 keycloak
Quando aparecerem as mensagens de inicialização normal, pressione Ctrl+C para sair dos logs sem parar o contêiner. Verifique a interface principal e a interface de administração:
curl -fsSI http://127.0.0.1:8080/
curl -fsS http://127.0.0.1:9000/health/ready | jq
curl -fsS http://127.0.0.1:9000/health/live | jq
ss -lnt | grep -E ':8080|:9000'
/health/ready deve retornar HTTP 200 com status UP. 8080 e 9000 devem escutar apenas em 127.0.0.1. A imagem oficial do Keycloak não instala curl para reduzir a superfície de ataque, então a verificação de saúde dentro do contêiner no Compose usa o método Bash TCP indicado na documentação oficial; as verificações no host ainda podem usar curl.
Se o Keycloak mostrar unhealthy, veja primeiro:
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q keycloak)" | jq
docker compose logs --tail=200 postgres keycloak
Não use restart: always para mascarar erros de senha do banco de dados, nome de host ou migração. Um contêiner que reinicia continuamente só torna os logs mais difíceis de ler.
Crie ou edite /etc/caddy/Caddyfile:
sso.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8080
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
}
}
Substitua o domínio pelo valor em .env. O Caddy define ou amplia X-Forwarded-For por padrão, e define X-Forwarded-Proto e X-Forwarded-Host; o Keycloak já analisa esses cabeçalhos via KC_PROXY_HEADERS=xforwarded. Não permita que clientes não confiáveis contornem o Caddy e se conectem diretamente a 8080.
Valide e recarregue:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo systemctl status caddy --no-pager
curl -fsSI https://sso.example.com/
Se a emissão do certificado falhar, verifique se o DNS já entrou em vigor, se as portas 80/443 estão ocupadas por outros serviços, se o grupo de segurança da nuvem as libera e se um registro AAAA errado aponta as requisições para um IPv6 inacessível. Para configuração multisite e solução de problemas de certificado, consulte o guia completo de HTTPS automático do Caddy.
O Keycloak adverte oficialmente de forma explícita contra expor a porta de administração 9000 por meio de um proxy reverso. Não configure reverse_proxy 127.0.0.1:9000 nem o libere no grupo de segurança.
Abra:
https://sso.example.com/admin/
Faça login com KC_BOOTSTRAP_ADMIN_USERNAME e KC_BOOTSTRAP_ADMIN_PASSWORD de .env. O Keycloak atual trata as contas criadas por parâmetros de inicialização como administradores temporários; elas devem ser usadas apenas para criar o realm master na primeira vez, e não são recriadas a cada inicialização só porque as variáveis de ambiente ainda existem.
Imediatamente após o login, conclua o seguinte:
- Crie um novo administrador permanente no realm
master, usando uma conta pessoal em vez de umadmincompartilhado; - Ative TOTP ou WebAuthn para o administrador permanente e confirme que consegue entrar novamente em uma janela anônima;
- Atribua ao administrador permanente apenas as funções administrativas de que ele precisa, evitando que contas do dia a dia tenham permissões além de suas responsabilidades;
- Após entrar com sucesso com o administrador permanente, exclua
temp-admin; - Exclua as duas linhas
KC_BOOTSTRAP_ADMIN_*de.enve reconstrua o contêiner do Keycloak; - Registre o processo de recuperação do administrador permanente na documentação de operações offline da equipe.
Depois de editar .env para remover as variáveis do administrador temporário, exclua também as duas linhas de variáveis de ambiente correspondentes de compose.yaml e execute:
cd /opt/keycloak
docker compose config --quiet
docker compose up -d --force-recreate keycloak
docker compose logs --tail=100 keycloak
Excluir apenas as variáveis de ambiente não remove automaticamente a conta temporária; você precisa excluí-la manualmente no console de administração. Por outro lado, não exclua a conta temporária antes de verificar o administrador permanente, ou você pode se trancar fora do sistema.
Não coloque usuários comuns e aplicações de negócio diretamente no realm master. O master é usado principalmente para gerenciar outros realms; o negócio deve criar um realm separado, por exemplo company.
No menu suspenso de realm no canto superior esquerdo, selecione Create realm:
- Realm name:
company - Enabled: ativado
O nome do realm passa a fazer parte das URLs de endpoints públicos, então tente não alterá-lo após a criação. Use um nome ASCII curto em minúsculas e não inclua segredos da empresa nem descrições de ambiente.
Após criar, verifique pelo menos os seguintes itens:
- Realm settings → Login: se autorregistro, senha esquecida e login por e-mail são permitidos;
- Realm settings → Email: configure SMTP e teste os e-mails de redefinição de senha;
- Authentication → Policies: políticas de comprimento, caracteres e histórico de senhas;
- Realm settings → Security defenses: ative a detecção de força bruta e defina limites razoáveis;
- Realm settings → Tokens: ajuste Access Token, SSO Session e Offline Session conforme o risco;
- Events: registre falhas de login e alterações administrativas, e planeje um período de retenção.
Não ative ao mesmo tempo autorregistro, senhas frouxas, sessões longas e tentativas ilimitadas por "conveniência de login". Depois que o SSO centraliza o ponto de entrada, a segurança desse ponto de entrada também afeta todas as aplicações conectadas.
Suponha que a aplicação a integrar esteja em:
https://app.example.com
A documentação dela exige que a URI de redirecionamento seja:
https://app.example.com/oauth/callback
Mude para o realm company e vá em Clients → Create client:
- Client type:
OpenID Connect - Client ID:
internal-app - Client authentication: ativado para aplicações do lado do servidor; desativado para clientes públicos de navegador puro conforme a documentação da aplicação
- Standard flow: normalmente ativado para login com código de autorização no navegador
- Direct access grants: desativado, a menos que haja necessidade clara
- Valid redirect URIs:
https://app.example.com/oauth/callback - Web origins: apenas
https://app.example.com
Após salvar, aplicações do lado do servidor podem obter o Client Secret em Credentials. O segredo só pode ficar em variáveis de ambiente do lado do servidor ou em um sistema de gestão de segredos, nunca em JavaScript do navegador, repositórios públicos ou imagens de frontend.
As URIs de redirecionamento devem seguir a documentação oficial da aplicação. O mais seguro é informar endereços exatos; não escreva * só para economizar esforço. O guia oficial de administração do Keycloak adverte explicitamente que usar redirecionamentos totalmente curinga em produção facilita que atacantes construam redirecionamentos maliciosos.
A maioria das aplicações precisa apenas dos quatro itens a seguir:
| Parâmetro | Valor de exemplo |
|---|---|
| Issuer | https://sso.example.com/realms/company |
| Discovery URL | https://sso.example.com/realms/company/.well-known/openid-configuration |
| Client ID | internal-app |
| Client Secret | O valor gerado em Credentials |
Primeiro verifique o documento de descoberta a partir do VPS ou do servidor da aplicação:
curl -fsS \
https://sso.example.com/realms/company/.well-known/openid-configuration \
| jq '{issuer,authorization_endpoint,token_endpoint,jwks_uri,end_session_endpoint}'
O issuer na saída deve ser:
https://sso.example.com/realms/company
Se ele mostrar http://127.0.0.1:8080, um nome de contêiner interno ou o domínio errado, corrija primeiro KC_HOSTNAME e os cabeçalhos do proxy, e depois conecte a aplicação. Não desative a verificação de issuer ou TLS na aplicação para contornar o erro.
O Keycloak costuma ter três camadas de objetos de permissão:
- Group: representa uma estrutura organizacional ou um conjunto de pessoas, por exemplo
engineering,finance; - Realm Role: uma função compartilhada entre várias aplicações, por exemplo
employee,security-auditor; - Client Role: pertence apenas a um cliente específico, por exemplo
grafana-admin,wiki-editor.
Recomenda-se adicionar usuários a grupos e depois mapear funções para grupos, em vez de atribuir manualmente dezenas de funções a cada usuário. Por exemplo:
Group: engineering
├─ Realm Role: employee
├─ Client Role: grafana-viewer
└─ Client Role: internal-app-editor
Assim, quando um funcionário muda de cargo, só o grupo precisa ser ajustado. A aplicação ainda deve validar o token, o issuer, a audience, a assinatura e as funções no próprio backend; "o usuário consegue entrar pelo Keycloak" não significa "o usuário tem automaticamente permissões de administrador da aplicação".
Se a aplicação não vê as funções esperadas, verifique se o Client Scope e o Protocol Mapper colocam os claims correspondentes no ID Token ou no Access Token. Não coloque indiscriminadamente todas as funções e atributos de usuário no token; cookies ou cabeçalhos de requisição grandes demais podem fazer o proxy reverso retornar 431 Request Header Fields Too Large.
Um ponto de entrada de identidade que controla vários sistemas deve, no mínimo, exigir MFA dos administradores. Você pode ativar Configure OTP em Authentication → Required actions e depois exigir que grupos de usuários específicos configurem TOTP por meio de ações de usuário padrão ou de um fluxo de autenticação condicional.
As políticas de senha podem partir da seguinte base e ser ajustadas ao risco da organização:
- mínimo de 14 caracteres;
- rejeitar senhas usadas recentemente;
- ativar detecção de força bruta;
- exigir MFA dos administradores;
- não compartilhar contas de administrador;
- usar validade curta para links de redefinição por e-mail;
- manter Access Tokens curtos e confiar em Refresh Tokens seguros para renovação;
- encurtar sessões ociosas e sessões máximas para aplicações de alto risco.
Não configure às cegas Access Tokens de várias horas. Depois que um token vaza, ele pode ser usado até expirar ou ser efetivamente revogado. Também não se limite a encurtar os Access Tokens enquanto deixa as aplicações registrarem Client Secrets e Refresh Tokens.
Vá em Realm settings → Email e preencha SMTP Host, Port, From, conta de autenticação e método de criptografia. Clique em testar conexão e crie de fato um usuário de teste comum para verificar:
- Os e-mails de verificação são entregues;
- Os links de redefinição de senha usam o domínio HTTPS correto;
- Os links não podem ser usados após expirar;
- Os e-mails não vazam nomes de host internos;
- O domínio remetente tem SPF, DKIM e DMARC configurados.
A senha SMTP, assim como a senha do banco de dados, é configuração sensível. Se for injetada por variáveis de ambiente ou KeyStore, não a vaze na saída de docker compose config, no histórico do terminal ou nos logs de monitoramento.
Este artigo ativa health e metrics em tempo de build. O host pode verificar:
curl -fsS http://127.0.0.1:9000/health/ready | jq
curl -fsS http://127.0.0.1:9000/health/live | jq
curl -fsS http://127.0.0.1:9000/metrics | head
Os quatro endpoints de saúde comuns têm significados diferentes:
| Endpoint | Uso |
|---|---|
/health/started | Sonda de inicialização, determina se o processo de inicialização terminou |
/health/live | Sonda de vivacidade, determina se o processo ainda pode ser executado |
/health/ready | Sonda de prontidão, determina se pode aceitar novo tráfego |
/health | Informações de saúde agregadas |
Uma falha temporária de ready não significa necessariamente que o contêiner deva ser reiniciado imediatamente; quando o banco de dados tem uma breve oscilação, reiniciar amplifica a falha. A documentação oficial também indica que as verificações de saúde do contêiner baseadas em ready servem para determinar se deve aceitar tráfego e não devem ser equiparadas diretamente a "deve reiniciar".
Externamente, você também deve verificar a partir de outra máquina:
curl -fsS \
https://sso.example.com/realms/company/.well-known/openid-configuration \
>/dev/null
Verificações externas podem detectar falhas de DNS, certificado, Caddy e enlace de rede pública, enquanto o /health/ready local só mostra que o próprio Keycloak está pronto. Você pode conectar verificações de vivacidade externas ao Uptime Kuma e enviar métricas de JVM, pool de conexões do banco de dados e taxa de erros de login para o Prometheus ou para a sua plataforma de monitoramento existente.
O banco de dados do Keycloak contém dados sensíveis como usuários, hashes de senha, Client Secrets, chaves de assinatura de realm e sessões. Os backups devem ser criptografados, ter acesso restrito e ser copiados para outra máquina ou armazenamento de objetos.
Crie o diretório de backup:
sudo install -d -m 700 -o "$USER" -g "$USER" /opt/keycloak/backups
cd /opt/keycloak
Execute um backup lógico:
set -a
. ./.env
set +a
BACKUP_FILE="/opt/keycloak/backups/keycloak-$(date +%F-%H%M%S).dump"
docker compose exec -T postgres \
pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc \
> "$BACKUP_FILE"
chmod 600 "$BACKUP_FILE"
pg_restore --list "$BACKUP_FILE" | head
unset POSTGRES_PASSWORD KC_BOOTSTRAP_ADMIN_PASSWORD
Também faça backup do seguinte, mas não misture o .env em texto simples com documentação pública:
compose.yaml,Containerfilee o Caddyfile;- o
.envcriptografado ou a configuração do sistema externo de gestão de segredos; - temas personalizados, JARs de Provider e suas versões exatas;
- o dump do PostgreSQL;
- números de versão, passos de recuperação e o registro do último simulado.
A exportação JSON de realm do Keycloak pode auxiliar na migração e na revisão de configuração, mas a documentação oficial afirma explicitamente que ela tem limitações de consistência e de escopo de dados: exportações online não garantem consistência e não incluem todas as sessões, eventos, estados de fluxo de trabalho e tokens revogados. Portanto, exportações de realm não substituem backups do banco de dados.
Se uma exportação CLI completa for realmente necessária, agende primeiro uma janela de manutenção para parar o Keycloak e depois execute o comando oficial export. A exportação parcial do console de administração mascara senhas e Client Secrets e também não é adequada como backup completo de recuperação de desastres.
Um simulado de recuperação deve verificar pelo menos:
- Criar um PostgreSQL vazio em um ambiente isolado;
- Importar o backup usando
pg_restore; - Iniciar com a mesma versão do Keycloak;
- Verificar realms, usuários, clientes, funções e chaves de assinatura;
- Concluir login, renovação e logout com uma aplicação de teste;
- Registrar o tempo de recuperação e os pontos de falha.
Se um backup nunca foi restaurado com sucesso, ele é apenas um "arquivo possivelmente utilizável". Você pode consultar o guia de backups e simulados de recuperação em VPS para encadear banco de dados, configuração e armazenamento externo em uma tarefa agendada.
Um serviço de identidade não deve ficar muito tempo em versões antigas, mas você também não deve baixar uma imagem nova diretamente sem backups e um plano de reversão. Antes de atualizar:
- Leia as notas de versão, o guia de atualização e os avisos de segurança da versão de destino;
- Faça backup do PostgreSQL, da configuração, dos temas personalizados e dos Providers;
- Verifique a atualização em um ambiente de teste usando uma cópia do backup de produção;
- Verifique se as extensões personalizadas suportam a versão de destino;
- Registre o ID da imagem atual, a versão do Keycloak e a versão do PostgreSQL;
- Prepare a recuperação do banco de dados, não apenas a reversão da imagem.
Verifique a versão e a imagem atuais:
cd /opt/keycloak
docker compose exec keycloak /opt/keycloak/bin/kc.sh --version
docker compose images
docker inspect local/keycloak:26.7.2 --format '{{.Id}}'
Ao atualizar, altere as duas ocorrências da versão do Keycloak em Containerfile, construa primeiro mas não exclua a imagem antiga imediatamente:
docker compose build --pull keycloak
docker compose up -d keycloak
docker compose logs -f --tail=200 keycloak
Após concluir as verificações de saúde, o login no console de administração e um login OIDC real, limpe a imagem antiga. A inicialização do Keycloak pode modificar o esquema do banco de dados, então simplesmente voltar à imagem antiga pode não reverter; a abordagem confiável é restaurar o banco de dados anterior à atualização e usar a imagem antiga junto com ele.
Primeiro confirme se o Keycloak está em execução e se a porta escuta apenas no loopback:
cd /opt/keycloak
docker compose ps
docker compose logs --tail=200 keycloak
curl -fsSI http://127.0.0.1:8080/
ss -lnt | grep ':8080'
Se acessar 127.0.0.1:8080 a partir do host também falhar, o problema está no Keycloak, no banco de dados ou no Compose, não no Caddy. Se a verificação local estiver normal, verifique o Caddyfile, o SELinux/AppArmor e os logs do Caddy.
Confirme:
KC_HOSTNAME: https://${KC_HOSTNAME}
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
Também confirme que os usuários só podem acessar o serviço pelo Caddy e que nenhum outro proxy sobrescreve X-Forwarded-Proto. Se houver um CDN na frente do Caddy, confie apenas nas faixas de saída publicadas oficialmente pelo CDN, não em cabeçalhos de encaminhamento de clientes arbitrários.
Compare o redirect_uri realmente enviado pela aplicação com as Valid redirect URIs do cliente do Keycloak. Protocolo, domínio, porta, caminho e barra final podem afetar a correspondência:
https://app.example.com/oauth/callback
https://app.example.com/oauth/callback/
São dois endereços diferentes. Prefira adicionar endereços exatos; não use * como solução temporária e esqueça de restringir depois.
Verifique o documento de descoberta:
curl -fsS \
https://sso.example.com/realms/company/.well-known/openid-configuration \
| jq -r .issuer
O Issuer configurado na aplicação deve coincidir caractere por caractere. Não trate a Discovery URL como Issuer nem misture o caminho antigo /auth/realms/....
Verifique na ordem:
- Se o usuário pertence ao Group correto;
- Se o Group mapeia Realm Roles ou Client Roles;
- Se a aplicação lê o ID Token ou o Access Token;
- Se o Client Scope / Mapper inclui os claims necessários;
- Se a aplicação espera
realm_access.roles,resource_accessou claims personalizados; - Se o usuário entrou novamente para obter um token novo após alterar as funções.
Não julgue a segurança da autorização apenas decodificando o JWT no navegador. O backend também deve validar a assinatura, o issuer, a audience, a expiração e as regras de autorização.
Verifique os logs mas não imprima senhas diretamente:
cd /opt/keycloak
docker compose logs --tail=200 postgres keycloak
docker compose exec postgres pg_isready -U keycloak -d keycloak
Se o volume do banco de dados já foi inicializado, alterar depois apenas a senha em .env não mudará automaticamente a senha do usuário do banco de dados. Você deve realizar explicitamente uma alteração de senha, ou reconstruir quando confirmar que não há dados e tiver autorização; não exclua o volume como passo comum de solução de problemas.
Confirme que o mem_limit: 2g do Compose está em vigor:
docker inspect "$(docker compose ps -q keycloak)" \
--format '{{.HostConfig.Memory}}'
docker stats --no-stream
O contêiner oficial calcula o heap com base no limite de memória; sem limite, a JVM pode expandir com base na memória total do host. Se realmente houver OOM, analise primeiro a concorrência de login, o cache, os Providers personalizados e a latência do banco de dados, e depois ajuste o limite; não adicione apenas Swap para mascarar o problema.
Verificações de prontidão não substituem verificações reais de negócio. Continue verificando:
- DNS público e certificados;
- Discovery URL;
- O fluxo de código de autorização do cliente de teste;
- LDAP/fontes de identidade externas;
- Serviços SMTP ou MFA;
- O redirecionamento da aplicação e a validação do token no backend.
Recomenda-se usar um realm de teste dedicado ou uma conta de teste para monitoramento sintético de login, para que os scripts de monitoramento não tenham permissões de administrador de produção.
Confirme cada item antes de lançar:
- O Keycloak usa uma versão explícita
26.7.2, nãolatest; - O PostgreSQL não mapeia portas públicas;
-
8080e9000se ligam apenas a127.0.0.1; - O Caddy HTTPS funciona e o domínio coincide exatamente com
KC_HOSTNAME; -
KC_PROXY_HEADERS=xforwardedestá configurado; - A porta de administração
9000não está exposta pelo Caddy; - Foi criado um administrador pessoal permanente e o MFA foi ativado;
- O administrador temporário foi excluído e as variáveis de inicialização foram removidas;
- Usuários de negócio e aplicações não estão no realm
master; - As URIs de redirecionamento OIDC e as Web Origins usam valores exatos;
- Os Client Secrets não entraram no frontend, no Git ou nos logs;
- Estão ativadas políticas de senha, detecção de força bruta e durações de sessão razoáveis;
- SMTP, redefinição de senha e MFA foram realmente testados;
- O banco de dados e a configuração têm backups criptografados em outra máquina;
- Foi concluído um simulado de recuperação em ambiente isolado;
- Tanto as verificações de saúde internas quanto o caminho de login externo estão monitorados;
- Existe um plano de reversão em nível de banco de dados antes das atualizações.
O contêiner oficial recomenda um limite de memória de 2 GB para pequenas implantações de produção, com o heap máximo da JVM, por padrão, em torno de 70% do limite do contêiner. Ambientes de teste podem ser menores, mas quando Keycloak, PostgreSQL e o sistema compartilham a máquina, todo o VPS deve partir de 4 GB; para suportar os logins críticos de uma equipe, 8 GB deixam uma folga mais razoável para o banco de dados, o cache e as atualizações. A capacidade final deve se basear em testes de carga com logins simultâneos reais, políticas de hash de senha, fontes de identidade e plugins.
Não é recomendado. start-dev reduz os limites de segurança para o desenvolvimento local. A produção deve usar start, configurar um nome de host fixo, HTTPS ou terminação TLS controlada no proxy reverso, um banco de dados de produção, e seguir a recomendação oficial de executar primeiro build e depois start --optimized.
Porque este artigo usa terminação TLS na borda: a conexão do navegador com o Caddy é HTTPS, e a do Caddy com o Keycloak na mesma máquina, ligada apenas ao loopback, é HTTP. O modo de produção do Keycloak desativa HTTP por padrão, então ele precisa ser ativado explicitamente, junto com o nome de host externo completo e KC_PROXY_HEADERS=xforwarded. A internet pública não pode acessar 8080 diretamente.
Não. A documentação oficial afirma que as exportações têm limitações de consistência e de escopo de dados e não incluem todos os eventos, sessões persistentes, estados de fluxo de trabalho e tokens revogados. A recuperação de desastres deve se concentrar em backups criptografados do PostgreSQL, com as exportações de realm como complemento para migração ou revisão de configuração.
Sim. Cada aplicação normalmente tem seu próprio cliente, configurado com URIs de redirecionamento exatas, Web Origins, segredos e funções. Ambientes com vários departamentos ou limites de segurança muito diferentes podem ser divididos em vários realms, mas usuários, sessões e configuração ficam isolados entre realms, então considere a sincronização de contas e os custos operacionais antes de dividir.
Pode servir como ponto de partida para equipes pequenas que aceitem breves interrupções de login, mas não é alta disponibilidade. Se as sessões existentes continuam utilizáveis depende do design de tokens e sessões da aplicação; novos logins, renovações de token e logouts costumam ser afetados por falhas do Keycloak. Atividades críticas devem implantar vários nós do Keycloak, um banco de dados externo de alta disponibilidade, balanceamento de carga e um processo de recuperação ensaiado.
- Downloads e versão atual do Keycloak
- Executar o Keycloak em um contêiner
- Configuração de produção do Keycloak
- Configuração de proxy reverso do Keycloak
- Keycloak Hostname v2
- Bancos de dados e plataformas suportados pelo Keycloak
- Verificações de saúde do Keycloak
- Administrador temporário e recuperação do Keycloak
- Importação e exportação de realms do Keycloak
- Documentação de reverse_proxy do Caddy
O critério de uma implantação bem-sucedida do Keycloak não é "o console de administração abre", mas sim que o nome de host externo esteja correto, as URIs de redirecionamento estejam restritas, o administrador temporário tenha sido limpo, os processos de MFA e desligamento de contas sejam executáveis, o banco de dados possa ser recuperado, as atualizações possam ser revertidas e o caminho real de login OIDC esteja monitorado. Primeiro faça esse ciclo mínimo funcionar e depois conecte GitLab, Grafana, Jenkins ou aplicações auto-hospedadas; a expansão posterior será muito mais segura.