---
name: cabal-server-arquitetura
description: "Cabal private server layout — SSH/Docker access path, the opcode proxy in front of LoginSvr, and which paths actually persist"
metadata: 
  node_type: memory
  type: project
  originSessionId: 153bd067-f5ce-4a37-9378-d46c0afa3789
  modified: 2026-08-17T14:44:39.922Z
---

Servidor Cabal Online privado. Acesso: VM VirtualBox "Cabal-EP35-Docker" via
`ssh -p 2222 root@127.0.0.1`, e dentro dela o container `docker exec cabal_main`
(imagem `x10plays/cabal-ep33`, restart policy `always`, rede bridge).

**Proxy de opcode (montado em agosto/2026).** O cliente moderno manda o opcode
5383, que a tabela de dispatch do LoginSvr EP33 rejeita (só aceita <= 3999). Um
proxy MITM em Python escuta na 35003 e reescreve 5383 -> 3383; o LoginSvr foi
movido para a 45003 (`/etc/cabal/LoginSvr_01.ini`). O proxy vive em
`/etc/cabal_scripts/opcode_proxy/opcode_proxy.py`, registrado no supervisor por
`/etc/cabal_scripts/cabal_services/cabal_opcode_proxy.conf`, log em
`/var/log/cabal/opcode_proxy.log`.

Detalhe crítico: a tabela de chaves XOR do LoginSvr é regerada com semente
aleatória a cada start, então **nunca pode ser embutida no código** — o proxy a
extrai do processo vivo com gdb (por isso o container tem `CAP_SYS_PTRACE`) e
re-extrai sozinho quando o PID do LoginSvr muda.

**O que persiste e o que não.** Só os bind-mounts sobrevivem à recriação do
container: `/etc/cabal`, `/etc/cabal_bin`, `/etc/cabal_scripts`,
`/etc/cabal_structure`, `/var/log/cabal` (respectivamente `/home/data_main/cabal*`
e `/home/data_main/logs` na VM). Qualquer coisa fora disso está na camada
gravável e some. Foi exatamente essa a causa de um bug difícil: as libs do
extender EP33->EP35 estavam só em `/usr/lib/cabal/`, o `LD_PRELOAD` falhava em
silêncio (glibc ignora entrada ausente) e o cliente fechava ao entrar no
personagem — hoje elas moram em `/etc/cabal_bin/lib/`.

Nenhum serviço do jogo tem `autostart=true` no supervisor; são iniciados por
orquestração externa, em ordem imprevisível. Por isso o proxy foi feito para não
depender de ordem de inicialização.

**NUNCA rodar `supervisorctl restart all` / `start all` dentro do cabal_main.**
O supervisor tem um monte de programa definido que não deve rodar de verdade —
`WorldSvr_02_*`, `WorldSvr_03_*`, `gms_proxy_*`, e copias duplicadas `_02`/`_03`
de varios DBAgent/ChatNode/PartySvr/AgentShop. "restart all"/"start all" tenta
subir TUDO isso de uma vez, gera uma tempestade de spawn error (porta/recurso
em conflito), e o pior: **derruba os canais WorldSvr_01_01..20 que estavam
saudaveis** junto (viram FATAL, "too many start retries too quickly").
Confirmado ao vivo em 17/ago/2026 — recuperacao exigiu reset da VM inteira
(detalhe abaixo). **Reiniciar sempre por nome explicito**
(`supervisorctl restart LoginSvr_01`, etc.), nunca com `all` nem wildcard.

**Cadeia de dependencia do WorldSvr, descoberta ao vivo tentando religar depois
do incidente acima.** Um canal WorldSvr_01_XX so' inicializa se, nessa ordem,
conseguir linkar com: `GlobalMgrSvr` (38181, duas vezes) -> algo em 38190 ->
**`ChatNode_01`** (48111, `pLinkLayer4CHAT`) -> algo em 38140 ->
**`AgentShop_01`** (38151, `pLinkLayer4AgentShop`) -> (pode ter mais depois
disso, nao foi necessario descobrir). Se qualquer um desses estiver fora do
ar, o WorldSvr da' `ACE_ASSERT ... LinkingLinkLayer ... Aborting` e morre com
SIGABRT na hora. Ordem pra religar do zero: `LoginSvr_01`, `GlobalMgrSvr`,
`ChatNode_01`, `AgentShop_01`, `DBAgent_01`, `ChatDBAgent_01`,
`CashDBAgent_01`, `EventDBAgent`, `GlobalDBAgent`, `PCBangDBAgent`,
`PartySvr_01`, `RockAndRoll`, `StunSvr`, `EventMgrSvr` — so' depois disso
tentar `WorldSvr_01_01` (ou os outros canais que precisar).

**Existe um `cabal_main_old_backup`** (mesma imagem `x10plays/cabal-ep33`,
mesmo mapeamento de porta) que **tambem tem restart policy `always`** — se a
VM reiniciar e ele subir ANTES do `cabal_main` de verdade, ele fica com as
portas (ex.: 35001) e o `cabal_main` real fica travado num loop de
`Bind for 0.0.0.0:35001 failed: port is already allocated`, nunca sobe.
Depois de qualquer reset/reboot da VM, **conferir `docker ps -a`**: se
`cabal_main_old_backup` estiver `Up` e `cabal_main` `Exited (255)`, e' isso —
`docker stop cabal_main_old_backup` seguido de `docker start cabal_main`
resolve. Esse backup antigo continua sendo um item pendente pra decidir o
destino (desativar restart policy dele de vez, ou remover), nunca foi feito.

**Incidente de trava total da VM (17/ago/2026).** Depois do "restart all"
acima, a VM inteira ficou incapaz de criar processo novo — nem `/bin/true`
rodava por SSH, nem ler `/proc/loadavg` via redirecionamento puro do bash
(sem fork nenhum) respondia. `echo` sem redirecionamento (builtin do shell)
ainda funcionava, entao o daemon SSH em si nao tinha morrido, so' o kernel/
scheduler da VM estava travado de verdade. Do host Windows, `VBoxManage
metrics query` nao tinha dado configurado, mas o processo `VBoxHeadless.exe`
real (achar via `Get-Process VBoxHeadless`, o de maior CPU acumulado — tinha
**3 processos VBoxHeadless.exe simultaneos**, os outros 2 devem ser zumbis de
starts anteriores) mostrou ~157% de CPU (de 400% possivel, 4 vCPU) quando
medido em tempo real (`$p1.CPU` antes/depois de um `Start-Sleep`) — alto mas
nao 100% travado, entao pode ter sido mais contencao de I/O/scheduler do que
CPU pura. **Solucao que funcionou**: `VBoxManage controlvm "Cabal-EP35-Docker"
reset` (reset forcado, tipo botao fisico) a partir do host Windows — a VM
voltou a responder em ~1min. Depois do reset, precisou resolver o problema do
`cabal_main_old_backup` (acima) e religar os servicos manualmente (nada sobe
sozinho).

Ver [[cabal-eventpass]] pra o contexto de o que estava sendo testado quando
isso aconteceu (nao ficou claro qual ação específica desencadeou a trava —
foi depois de uma sequência de `supervisorctl restart LoginSvr_01` que
travou a própria conexão SSH, então pode ter sido cumulativo com o "restart
all" anterior, não necessariamente causado só por ele).

Relacionado: [[user-speaks-portuguese]], [[cabal-rates-onde-editar]]
