Este documento descreve todas as variáveis de ambiente, arquivos de configuração, valores padrão e overrides por ambiente do IterBot.
- Visão Geral
- Variáveis de Ambiente
- Docker Secrets
- Arquivo .env
- Configuração do Traefik
- Campos Criptografados
- Configurações Obrigatórias vs Opcionais
- Valores Padrão
- Overrides por Ambiente
- Configuração do Celery Beat
- Configuração do Logging
O IterBot utiliza django-environ para carregar configurações, com a seguinte ordem de precedência (maior para menor):
- Docker Secrets — arquivos em
/run/secrets/(produção) - Variáveis de ambiente —
os.environ - Arquivo
.env— carregado automaticamente pordjango-environ - Valores padrão — definidos em
config/env.py
A configuração é centralizada no módulo config/env.py, que define dataclasses para cada grupo de configuração (DjangoSettings, DatabaseSettings, WahaSettings, etc.) e consolida tudo em AppConfig.
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
DJANGO_SECRET_KEY |
Sim (prod) | Chave secreta para sessões e assinatura criptográfica do Django. Em produção, usar Docker Secret. | django_secret_key |
ENCRYPTION_KEY |
Sim (prod) | Chave Fernet dedicada para criptografia de campos sensíveis no banco. Usar Docker Secret. Sem ela, usa SECRET_KEY como fallback (menos seguro). |
encryption_key |
DEBUG |
Não | Modo debug. Nunca usar True em produção. |
— |
ALLOWED_HOSTS |
Não | Hostnames permitidos, separados por vírgula. Ex: localhost,127.0.0.1,meudominio.com |
— |
DOMAIN |
Não | Domínio principal da aplicação. Usado pelo Traefik para roteamento. | — |
PORTAL_BASE_URL |
Sim (prod) | URL completa do portal de empresas (com protocolo). Obrigatória quando DEBUG=False. |
— |
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
DATABASE_URL |
Condicional | URL de conexão PostgreSQL. Ignorada se postgres_password secret existir. |
— |
POSTGRES_DB |
Não | Nome do banco de dados. | — |
POSTGRES_USER |
Não | Usuário do banco de dados. | — |
POSTGRES_HOST |
Não | Host do PostgreSQL. | — |
POSTGRES_PORT |
Não | Porta do PostgreSQL. | — |
| — | — | Senha do PostgreSQL. Lida exclusivamente do Docker Secret. | postgres_password |
Nota: Quando o Docker Secret
postgres_passwordestá disponível, aDATABASE_URLé construída automaticamente a partir dePOSTGRES_USER,POSTGRES_HOST,POSTGRES_PORT,POSTGRES_DBe o secret. Caso contrário, usaDATABASE_URLdiretamente.
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
REDIS_URL |
Não | URL de conexão Redis. Usada como broker do Celery e cache em produção. | — |
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
WAHA_URL |
Não | URL base da API WAHA. | — |
WAHA_API_KEY |
Não | Chave de autenticação da API WAHA. | waha_api_key |
WAHA_SESSION_NAME |
Não | Nome da sessão WhatsApp no WAHA. Cada sessão representa um número diferente. | — |
WAHA_TIMEOUT_SECONDS |
Não | Timeout em segundos para requisições à API WAHA. | — |
WAHA_DASHBOARD_USERNAME |
Não | Usuário para o dashboard do WAHA. | — |
WAHA_DASHBOARD_PASSWORD |
Não | Senha para o dashboard do WAHA. | waha_dashboard_password |
WHATSAPP_SWAGGER_USERNAME |
Não | Usuário para a documentação Swagger do WAHA. | — |
WHATSAPP_SWAGGER_PASSWORD |
Não | Senha para a documentação Swagger do WAHA. | waha_swagger_password |
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
BOT_DASHBOARD_USERNAME |
Não | Usuário para o dashboard do bot (Django admin). | — |
BOT_DASHBOARD_PASSWORD |
Não | Senha para o dashboard do bot. | — |
DJANGO_ADMIN_USERNAME |
Não | Usuário administrativo do Django. | — |
DJANGO_ADMIN_PASSWORD |
Não | Senha administrativa do Django. | — |
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
EMAIL_BACKEND |
Não | Backend de email do Django. | — |
EMAIL_HOST |
Não | Host do servidor SMTP. | — |
EMAIL_PORT |
Não | Porta do servidor SMTP. | — |
EMAIL_USE_TLS |
Não | Habilitar TLS para SMTP. | — |
EMAIL_HOST_USER |
Não | Usuário SMTP. | — |
EMAIL_HOST_PASSWORD |
Não | Senha SMTP. | email_password |
DEFAULT_FROM_EMAIL |
Não | Email remetente padrão. | — |
EMAIL_PROVIDER |
Não | Provider principal de email: resend, ses, smtp, console. Padrão: console. |
— |
EMAIL_FALLBACK_PROVIDER |
Não | Provider de fallback para envio de email quando o provider principal falha. Valores: resend, ses, smtp, console. Vazio = sem fallback (comportamento padrão). |
— |
RESEND_API_KEY |
Não | Chave de API do Resend. | resend_api_key |
BREVO_API_KEY |
Condicional | Chave de API do Brevo (Sendinblue). Obrigatória quando EMAIL_PROVIDER=brevo. |
brevo_api_key |
Nota: A partir da migração Brevo (abr/2026),
EMAIL_BACKENDnão muda mais automaticamente com base em credenciais AWS. Toda entrega transacional passa porEMAIL_PROVIDER(Brevo por padrão) viainfra/email/factory.py, incluindo e-mails do allauth (interceptados porUTFPRAccountAdapter). Para usar SES como Django backend, configureEMAIL_BACKEND=django_ses.SESBackendexplicitamente.
Nota: Quando
EMAIL_FALLBACK_PROVIDERestá configurado, o sistema tenta automaticamente o provider de fallback se o primary falhar. O health check em/health/verifica ambos os providers.
| Variável | Obrigatória | Descrição | Docker Secret |
|---|---|---|---|
AWS_ACCESS_KEY_ID |
Não | Access key da AWS IAM. | — |
AWS_SECRET_ACCESS_KEY |
Não | Secret key da AWS IAM. | — |
AWS_DEFAULT_REGION |
Não | Região padrão da AWS. | — |
O IterBot usa Docker Secrets para gerenciar credenciais sensíveis em produção. Os secrets são montados como arquivos em /run/secrets/ dentro dos containers.
Os secrets são armazenados no diretório secrets/ na raiz do projeto:
secrets/
├── django_secret_key.txt # Chave secreta do Django
├── encryption_key.txt # Chave dedicada de criptografia de campos (Fernet)
├── postgres_password.txt # Senha do PostgreSQL
├── waha_api_key.txt # API key do WAHA
├── waha_dashboard_password.txt # Senha do dashboard WAHA
├── waha_swagger_password.txt # Senha do Swagger WAHA
├── email_password.txt # Senha do servidor SMTP
└── .gitignore # Ignora arquivos .txt, mantém .txt.example
# Copiar templates de exemplo
cp secrets/django_secret_key.txt.example secrets/django_secret_key.txt
cp secrets/postgres_password.txt.example secrets/postgres_password.txt
cp secrets/waha_api_key.txt.example secrets/waha_api_key.txt
cp secrets/waha_dashboard_password.txt.example secrets/waha_dashboard_password.txt
cp secrets/waha_swagger_password.txt.example secrets/waha_swagger_password.txt
# Gerar valores seguros
python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' > secrets/django_secret_key.txt
openssl rand -base64 32 > secrets/postgres_password.txt
openssl rand -base64 32 > secrets/waha_api_key.txt
openssl rand -base64 32 > secrets/waha_dashboard_password.txt
openssl rand -base64 32 > secrets/waha_swagger_password.txt| Secret | Arquivo | Container |
|---|---|---|
django_secret_key |
./secrets/django_secret_key.txt |
backend |
encryption_key |
./secrets/encryption_key.txt |
backend |
postgres_password |
./secrets/postgres_password.txt |
db, backend |
waha_api_key |
./secrets/waha_api_key.txt |
|
waha_dashboard_password |
./secrets/waha_dashboard_password.txt |
waha (via env) |
waha_swagger_password |
./secrets/waha_swagger_password.txt |
waha (via env) |
email_password |
./secrets/email_password.txt |
backend |
A função _get_secret_or_env() em config/env.py resolve cada valor na seguinte ordem:
- Docker Secret (
/run/secrets/{nome}) — se o arquivo existir - Variável de ambiente (
os.environ) - Valor padrão — definido no código
O projeto fornece dois templates:
.env.example— Template completo com descrições e exemplos. Use como referência..env.local— Template mínimo para desenvolvimento local com Docker Compose..env.production.example— Template para produção.
# Desenvolvimento local
cp .env.local .env
# Edite .env conforme necessário
# Produção
cp .env.production.example .env
# Preencha com valores reaisO django-environ carrega automaticamente o arquivo .env na raiz do projeto (config/env.py:44).
O Traefik atua como proxy reverso com TLS (Let's Encrypt) e BasicAuth.
infra/traefik/traefik.yml — Configuração estática do Traefik:
- Entry points:
web(porta 80) ewebsecure(porta 443) - TLS: CertResolver
letsencryptcom HTTP challenge - Logging: JSON format, nível INFO
- Docker provider: rede
web, containers não expostos por padrão (exposedByDefault: false)
Nota: O email do Let's Encrypt em
traefik.yml(admin@iterbot.example.com) deve ser alterado para o email real de produção.
infra/traefik/dynamic/middlewares.yml define:
| Middleware | Tipo | Descrição |
|---|---|---|
security-headers |
Headers | HSTS, XSS filter, content-type nosniff, frame deny, SSL redirect, custom frame options |
rate-limit |
RateLimit | 100 req/s com burst de 50 |
waha-auth |
BasicAuth | Protege o dashboard WAHA (/etc/traefik/users/waha-users.txt) |
admin-auth |
BasicAuth | Protege o admin Django e portal (/etc/traefik/users/admin-users.txt) |
Configurados via deployment/scripts/setup-htpasswd.sh:
secrets/users/waha-users.txt— Credenciais do WAHA dashboardsecrets/users/admin-users.txt— Credenciais do admin/portal
O módulo infra/security/ implementa criptografia simétrica (Fernet) para campos sensíveis no banco de dados:
EncryptedCharField—models.CharFieldcom criptografia automáticaEncryptedTextField—models.TextFieldcom criptografia automática
A chave de criptografia é resolvida na seguinte ordem de precedência:
- Docker Secret
encryption_key(/run/secrets/encryption_key) — recomendado em produção - Variável de ambiente
ENCRYPTION_KEY - Fallback para
DJANGO_SECRET_KEY— mantido por retrocompatibilidade, mas gera aviso de log
Quando ENCRYPTION_KEY está presente, o sistema usa MultiFernet combinando a nova chave com a chave legada derivada de SECRET_KEY. Isso garante que dados já criptografados continuem legíveis sem necessidade de migração. Para gerar uma chave:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Salvar o output em secrets/encryption_key.txtModelos que usam campos criptografados (em apps/bot/models.py):
| Modelo | Campo | Tipo |
|---|---|---|
BotConfiguration |
waha_api_key |
EncryptedCharField |
BotConfiguration |
dashboard_password |
EncryptedCharField |
BotConfiguration |
admin_password |
EncryptedCharField |
Atenção: A
ENCRYPTION_KEYé obrigatória em produção. Sem ela, o sistema usaSECRET_KEYcomo fallback (menos seguro). Se tantoENCRYPTION_KEYquantoSECRET_KEYforem rotacionadas ao mesmo tempo semMultiFernet, dados criptografados existentes se tornarão ilegíveis — rotacione uma chave por vez.
| Configuração | Motivo |
|---|---|
DJANGO_SECRET_KEY |
Sessões e assinatura criptográfica. Falha com valor inseguro. |
PORTAL_BASE_URL |
Geração de links no bot. Deve começar com http:// ou https://. O app falha ao iniciar sem ela em produção. |
ALLOWED_HOSTS |
Segurança do Django. Não usar * em produção. |
Docker Secrets (postgres_password, etc.) |
Credenciais de produção não podem estar em variáveis de ambiente. |
| Configuração | Valor Padrão | Nota |
|---|---|---|
DEBUG |
False |
Seguro por padrão |
REDIS_URL |
redis://redis:6379/0 |
Funciona com Docker Compose |
WAHA_URL |
http://waha:3000 |
Nome do container Docker |
WAHA_API_KEY |
dev-api-key |
Apenas para desenvolvimento |
WAHA_SESSION_NAME |
default |
Sessão padrão do WAHA |
WAHA_TIMEOUT_SECONDS |
5 |
Timeout de 5 segundos |
DATABASE_URL |
sqlite:///{BASE_DIR}/db.sqlite3 (caminho absoluto) |
str |
Os valores padrão são definidos em config/env.py com resolução em cascata: environ.Env() define defaults iniciais, _get_secret_or_env() aplica Docker secrets quando disponíveis, e dataclasses definem defaults efetivos para desenvolvimento local:
| Variável | Valor Padrão | Tipo |
|---|---|---|
DEBUG |
False |
bool |
DJANGO_SECRET_KEY |
"dev-secret-key-change-in-production" |
str |
ALLOWED_HOSTS |
"*" |
str |
DATABASE_URL |
"" (string vazia) |
str |
REDIS_URL |
"redis://redis:6379/0" |
str |
WAHA_URL |
"http://waha:3000" |
str |
WAHA_API_KEY |
"dev-api-key" |
str |
WAHA_SESSION_NAME |
"default" |
str |
WAHA_TIMEOUT_SECONDS |
5 |
int |
BOT_DASHBOARD_USERNAME |
"admin" |
str |
BOT_DASHBOARD_PASSWORD |
"password" |
str |
DJANGO_ADMIN_USERNAME |
"admin" |
str |
DJANGO_ADMIN_PASSWORD |
"admin" |
str |
DOMAIN |
"localhost" |
str |
PORTAL_BASE_URL |
"" (string vazia) |
str |
EMAIL_BACKEND |
"django.core.mail.backends.console.EmailBackend" |
str |
EMAIL_HOST |
"" (string vazia) |
str |
EMAIL_PORT |
587 |
int |
EMAIL_USE_TLS |
True |
bool |
EMAIL_HOST_USER |
"" (string vazia) |
str |
EMAIL_HOST_PASSWORD |
"" (string vazia) |
str |
DEFAULT_FROM_EMAIL |
"noreply@iterbot.example.com" |
str |
EMAIL_PROVIDER |
"console" |
str |
EMAIL_FALLBACK_PROVIDER |
"" (string vazia) |
str |
RESEND_API_KEY |
"" (string vazia) |
str |
AWS_ACCESS_KEY_ID |
"" (string vazia) |
str |
AWS_SECRET_ACCESS_KEY |
"" (string vazia) |
str |
AWS_DEFAULT_REGION |
"us-east-1" |
str |
WAHA_DASHBOARD_USERNAME |
"admin" |
str |
WAHA_DASHBOARD_PASSWORD |
"password" |
str |
WHATSAPP_SWAGGER_USERNAME |
"swagger" |
str |
WHATSAPP_SWAGGER_PASSWORD |
"password" |
str |
POSTGRES_DB |
"iterbot" |
str |
POSTGRES_USER |
"iterbot_user" |
str |
POSTGRES_HOST |
"db" |
str |
POSTGRES_PORT |
"5432" |
str |
Nota: O fallback para
DATABASE_URLésqlite:///{BASE_DIR}/db.sqlite3, usado apenas quando não há Docker Secretpostgres_passwordeDATABASE_URLnão está configurada.
| Configuração | Valor |
|---|---|
LANGUAGE_CODE |
"pt-br" |
TIME_ZONE |
"America/Sao_Paulo" |
USE_I18N |
True |
USE_TZ |
True |
DEFAULT_AUTO_FIELD |
"django.db.models.BigAutoField" |
WSGI_APPLICATION |
"waha_bot.wsgi.application" |
ROOT_URLCONF |
"waha_bot.urls" |
SITE_ID |
1 |
STATIC_URL |
"/static/" |
STATIC_ROOT |
BASE_DIR / "staticfiles" |
STATICFILES_STORAGE |
"whitenoise.storage.CompressedManifestStaticFilesStorage" |
KEY_PREFIX (em CACHES) |
"iterbot" |
CELERY_TASK_SERIALIZER |
"json" |
CELERY_RESULT_SERIALIZER |
"json" |
CELERY_ACCEPT_CONTENT |
["json"] |
Use .env.local como base:
cp .env.local .envConfigurações-chave para desenvolvimento:
| Variável | Valor Recomendado | Motivo |
|---|---|---|
DEBUG |
True |
Páginas de erro detalhadas |
ALLOWED_HOSTS |
localhost,127.0.0.1,backend |
Hostnames locais |
DOMAIN |
localhost |
Domínio local |
EMAIL_BACKEND |
django.core.mail.backends.console.EmailBackend |
Emails no terminal |
REDIS_URL |
redis://redis:6379/0 |
Container Docker |
Cache em desenvolvimento: Usa LocMemCache com location iterbot-dev-cache automaticamente quando DEBUG=True.
Banco de dados em desenvolvimento: Se não houver Docker Secret postgres_password e DATABASE_URL não estiver definida, o Django usará SQLite automaticamente.
Use .env.production.example como base:
cp .env.production.example .env
# Preencha com valores reais de produçãoConfigurações obrigatórias para produção:
| Variável | Valor | Motivo |
|---|---|---|
DEBUG |
False |
Segurança |
ALLOWED_HOSTS |
${DOMAIN},www.${DOMAIN} |
Apenas domínios de produção |
PORTAL_BASE_URL |
https://${DOMAIN} |
Links HTTPS no bot |
EMAIL_BACKEND |
django.core.mail.backends.smtp.EmailBackend |
Envio real de emails |
EMAIL_HOST |
email-smtp.us-east-1.amazonaws.com |
AWS SES |
EMAIL_FALLBACK_PROVIDER |
ses |
Fallback para SMTP quando Resend falha |
Nota: Em produção, se
AWS_ACCESS_KEY_IDeAWS_SECRET_ACCESS_KEYestiverem presentes, o backend de email muda automaticamente paradjango_ses.SESBackend— não é necessário configurarEMAIL_BACKENDmanualmente.
Configurações de segurança ativadas automaticamente em produção (DEBUG=False):
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")SECURE_SSL_REDIRECT = TrueSECURE_REDIRECT_EXEMPT = [r"^webhook/$"](webhook WAHA usa HTTP interno)SESSION_COOKIE_SECURE = TrueCSRF_COOKIE_SECURE = TrueSECURE_BROWSER_XSS_FILTER = TrueSECURE_CONTENT_TYPE_NOSNIFF = TrueX_FRAME_OPTIONS = "DENY"SECURE_HSTS_SECONDS = 31536000(1 ano)SECURE_HSTS_INCLUDE_SUBDOMAINS = TrueSECURE_HSTS_PRELOAD = True
Cache em produção: Usa RedisCache com a REDIS_URL configurada.
BasicAuth do Traefik: Protege rotas sensíveis (WAHA dashboard, Django admin) com camada adicional de autenticação além do Django auth. Configurado via deployment/scripts/setup-htpasswd.sh.
As tarefas agendadas são configuradas em waha_bot/settings.py:
| Tarefa | Cron | Descrição |
|---|---|---|
send-weekly-job-review |
Toda segunda-feira às 08:00 | Envio semanal de review de vagas |
check-waha-health |
A cada 5 minutos | Health check da sessão WAHA |
clean-old-health-checks |
Todo domingo às 02:00 | Limpeza de registros antigos |
O timezone do Celery é America/Sao_Paulo (herdado de TIME_ZONE).
O IterBot usa structlog com renderer JSON para logs estruturados. Configurado em waha_bot/settings.py:
| Logger | Nível (dev) | Nível (prod) |
|---|---|---|
django |
INFO |
INFO |
apps |
DEBUG |
INFO |
root |
INFO |
INFO |
Processadores structlog (em ordem):
merge_contextvars— Contexto do Correlation IDfilter_by_level— Filtro por nívelTimeStamper(fmt="iso")— Timestamps ISO 8601add_logger_name— Nome do loggeradd_log_level— Nível do logPositionalArgumentsFormatter— Formatação de argumentosStackInfoRenderer— Stack tracesformat_exc_info— Exceções formatadasUnicodeDecoder— Decodificação UnicodeJSONRenderer— Saída em JSON
| Middleware | Arquivo | Função |
|---|---|---|
CorrelationIdMiddleware |
infra/middleware/correlation_id.py |
Adiciona X-Correlation-ID a cada request/response e ao contexto structlog |
StructuredLoggingMiddleware |
infra/middleware/structured_logging.py |
Log JSON de requests/responses com duração, método, path e status |
| Serviço | Imagem | Porta | Descrição |
|---|---|---|---|
traefik |
traefik:v3.6 |
80, 443 (8080 apenas em dev) | Proxy reverso com TLS |
db |
postgres:15-alpine |
5432 (interno) | Banco de dados PostgreSQL |
redis |
redis:7-alpine |
6379 (interno) | Cache e broker Celery |
backend |
Build local (Python 3.11) | 8000 | Django + Gunicorn |
waha |
devlikeapro/waha |
3000 | WhatsApp HTTP API |
O Redis é configurado com:
appendonly yes— Persistência AOFmaxmemory 256mb— Limite de memóriamaxmemory-policy allkeys-lru— Evicção LRU
| Volume | Descrição |
|---|---|
postgres_data |
Dados do PostgreSQL |
redis_data |
Dados do Redis |
waha_sessions |
Sessões do WAHA |
traefik_certs |
Certificados Let's Encrypt |
Todos os serviços estão na rede web (bridge, subnet 172.20.0.0/16).
Para validar a configuração antes de iniciar os serviços:
make validate
# ou
bash deployment/scripts/validate_environment.shPara configuração inicial completa (secrets + validação):
make setup