# FreeSWITCH Imagem própria em `infrastructure/freeswitch/` (agente.md secao 19), rodando como serviço Docker `freeswitch` (container `b2bcall-freeswitch`). ## Por que pacotes prontos, e não compilar da fonte O servidor de desenvolvimento tem só ~1.9GB de RAM. Compilar FreeSWITCH (C/C++, dezenas de módulos) arriscaria OOM e levaria muito tempo. Em vez disso, a imagem usa os pacotes `.deb` pré-compilados do repositório oficial do SignalWire (`freeswitch.signalwire.com`), autenticado com `FREESWITCH_PAT` — exatamente o uso previsto para essa credencial (agente.md secao 11). O repositório do SignalWire tem pacotes para o codename `trixie`, então a imagem usa `debian:trixie-slim` como base (mesma versão do host, mas isso é coincidência — o container é isolado e poderia usar qualquer Debian suportado pelo repo). ## Manuseio do PAT (agente.md secao 11) `FREESWITCH_PAT` entra no build via **Docker BuildKit secret** (`--mount=type=secret,id=freeswitch_pat`), nunca como `ARG`/`ENV`. O arquivo de credenciais do apt (`/etc/apt/auth.conf.d/freeswitch.conf`, que contém o PAT em texto puro) é criado e apagado dentro do **mesmo** `RUN`, então nunca aparece em nenhuma camada da imagem final — verificado com `docker history --no-trunc`. `docker-compose.yml` declara o secret assim: ```yaml secrets: freeswitch_pat: environment: FREESWITCH_PAT ``` e o serviço `freeswitch` referencia `secrets: [freeswitch_pat]` em `build:`. ## Pacotes instalados ``` freeswitch-meta-vanilla # core + config de referência (a mesma usada em # praticamente todo tutorial/livro de FreeSWITCH) freeswitch-conf-vanilla # ⚠ Recommends de meta-vanilla, não Depends — # precisa ser listado explicitamente com # --no-install-recommends (foi um bug real # durante o setup: sem isso /etc/freeswitch # fica vazio e o container entra em crash loop) freeswitch-mod-callcenter # ACD (agente.md secao 37) freeswitch-mod-avmd # detecção de caixa postal/beep (secao 87) freeswitch-mod-curl # chamadas HTTP a partir do dialplan ``` `mod_xml_curl` está **instalado mas desativado** em `overrides/autoload_configs/modules.conf.xml` — o módulo se recusa a carregar sem pelo menos um binding com `gateway-url` configurada ("Binding has no url!"), e essa URL só existirá quando o `b2bcall-fs-config` for criado (fase "XML Curl", logo em seguida). Reativar lá. `mod_signalwire` foi removido da lista de módulos: é específico da nuvem do SignalWire, que não usamos (só o repositório de pacotes). ## Event Socket (agente.md secao 22) Senha alterada da padrão (`ClueCon`) para `${ESL_PASSWORD}` (gerado com `openssl rand`, vive só em `.env`) via `entrypoint.sh`, que faz um `sed` no `event_socket.conf.xml` **em runtime** — a senha real nunca é copiada para a imagem, só injetada via variável de ambiente do container. O entrypoint falha alto (`set -eu` + `${ESL_PASSWORD:?...}`) se a variável não estiver definida — nunca sobe com a senha padrão por engano. Porta 8021 **não é publicada no host** (`ports:` ausente no compose) — só alcançável por outros containers na rede interna do Docker Compose (`b2bcall_default`), pelo nome de serviço `freeswitch`. Isso satisfaz "NÃO pública... acesso somente pela aplicação autorizada" sem precisar de ACL adicional por enquanto (ACL fica como hardening futuro, ver TODO). ## O que NÃO foi feito nesta fase (fica para as próximas, por design) Seguindo a ordem do próprio `agente.md` (secao 232): esta fase só cobre "ter o FreeSWITCH rodando e alcançável". As próximas fases constroem em cima: - **Event Socket**: `b2bcall-fs-events`, conexão ESL permanente (secao 21). - **XML Curl**: `b2bcall-fs-config`, reativa `mod_xml_curl` apontando pra esse serviço (secao 26). - **Extensions/Trunks/Dialplan**: hoje o directory/dialplan estático da config vanilla continua com os 20 ramais de teste (1000-1019, senhas fracas — README do próprio pacote avisa isso). Como as portas SIP não estão publicadas no host, isso fica contido, mas precisa ser substituído por `mod_xml_curl` dinâmico antes de qualquer tronco/ramal real existir. - **mod_odbc_cdr**: não instalado ainda — só faz sentido junto da fase de CDR. ## Verificação manual ```bash source <(grep '^ESL_PASSWORD=' .env) docker exec b2bcall-freeswitch fs_cli -p "$ESL_PASSWORD" -x "status" docker exec b2bcall-freeswitch fs_cli -p "$ESL_PASSWORD" -x "module_exists mod_sofia" ```