[🛠] IT Operations #2: No servidor Linux da empresa, defini a operação antes de instalar os serviços
✨ Resumo do GPT-5.6 Sol
Um registro de como configurei disco, SSH interno e endereço estável em um Ubuntu Server dedicado; separei permissões de pessoas, AI Cells e runtimes de automação; e documentei toda a rede como base operacional que o Codex pode retomar.
Finalmente montei um servidor Linux dedicado aos serviços da empresa.
Mas o que fiz desta vez não foi apenas um computador capaz de iniciar o Ubuntu. Era mais uma base operacional para que pessoas, IA e serviços de automação trabalhassem ao mesmo tempo no mesmo servidor sem invadir as permissões nem o estado uns dos outros.
Quando consegui o SSD, minha ideia era simples: instalar Linux em um PC com Windows, conectar por SSH e transformá-lo em servidor. Logo comecei a pensar na GUI. Será que eu me arrependeria de insistir apenas em CLI para parecer um “servidor de verdade” quando precisasse fazer login no navegador ou usar Computer Use?
Ao analisar cada parte, percebi que o servidor precisar de GUI e eu precisar usar GUI eram questões completamente diferentes. Se OAuth ou login no Codex fosse necessário, bastaria abrir no navegador do MacBook a URL exibida na sessão SSH. Se precisasse de Computer Use, eu poderia executá-lo no Mac ou em um dispositivo de trabalho e deixar o Linux como o Runtime onde o resultado seria implantado.
Servidor não é uma máquina para exibir uma tela. É um ambiente que continua em execução.
UEFI, GPT e LVM preservando o disco do Windows
Até o USB de instalação me confundiu. Achei que, se o USB do Ventoy usasse MBR, o Ubuntu também seria instalado em MBR. Quando apareceu UEFI: USB, Partition 2 no menu de boot, nem sabia se aquele era o caminho correto.
O esquema de partição do USB e o do SSD que receberia o Ubuntu são independentes. Bastava iniciar o instalador pela opção UEFI e selecionar com precisão o SSD de destino. Não toquei no NVMe existente do Windows e criei a EFI System Partition, /boot, LVM e o root filesystem apenas no novo SSD de 250 GB.
O mais assustador não era a dificuldade do Linux, mas a possibilidade de apagar o disco errado. Ao ver até a partição Reservado pelo Sistema do Windows, ela parecia algo que poderia ser removido. Conferi novamente modelo e capacidade dos discos no instalador e escolhi somente o SSD dedicado ao Ubuntu. O disco do Windows permaneceu intacto.
Escolhi a instalação padrão do Ubuntu Server 24.04.4 LTS, nem minimized nem Desktop image. Sem GUI, ficou uma base centrada em SSH e systemd, pronta para receber um Docker Runtime depois.
Reserva DHCP e SSH interno antes de um endereço fixo
Durante a instalação, a LAN cabeada recebeu imediatamente um endereço por DHCP. No início, achei que Create bond faria o SSH conectar melhor ou fixaria o endereço. Mas um bond combina várias NICs para redundância ou soma de largura de banda. Não tem relação com fixar o endereço de uma única NIC cabeada.
Em vez de gravar uma static IP arbitrária no servidor, associei o endereço MAC da NIC a um IP interno por uma reserva DHCP no roteador principal. O servidor continua como DHCP client, mas recebe o mesmo endereço após cada reinicialização. O roteador também permite verificar conflitos com outros dispositivos reservados.
Também não expus o SSH à Internet. Criei uma chave Ed25519 exclusiva para o MacBook, comparei a host key do servidor com o console e a fixei ao endereço da rede interna. Não configurei forwarding externo da porta 22 no roteador.
Logo após a instalação, ssh.service apareceu como disabled, e por um momento achei que o SSH estivesse mal instalado. Na verdade, ssh.socket estava ativo e ouvindo a porta 22; o public-key login continuou funcionando repetidamente depois do reboot. Socket activation pode iniciar o serviço correspondente quando chega uma solicitação, então eu não deveria diagnosticar falha olhando apenas uma linha do estado do serviço.1
A diferença entre DHCP lease, reservation e IP–MAC binding que aprendi alguns dias antes ao corrigir a queda de Internet do roteador da empresa foi aplicada diretamente à base deste servidor. Receber um endereço e poder administrar uma máquina com segurança por ele são coisas diferentes.
Pessoas, AI Cells e serviços fora de uma única conta
Assim que o SSH funcionou, quase instalei Oh My Zsh, Powerlevel10k e meus alias pessoais como sempre. Então parei novamente.
A primeira conta criada durante a instalação pertence à empresa e serve para bootstrap e recuperação. Colocar nela meu shell cotidiano, o AI Runtime e o Operations Automation seria conveniente. Mas seria impossível distinguir quem executou o quê e com qual autoridade, e tudo ficaria preso quando entrasse outro responsável ou fosse necessário revogar uma conta.
Por isso, comecei separando as contas por estas regras.
administrador de bootstrap
└─ usado apenas para instalação e recuperação
usr-<person>
└─ conta usada por uma pessoa para SSH, sudo e desenvolvimento
aio-cell-<person>
└─ conta sob a qual um AI Cell pessoal funciona continuamente
svc-<domain>-<purpose>
└─ Runtime de aplicação, importer de dados ou broker de operações restritas
Também foi intencional não colocar o nome da empresa nem o cargo no username. A pessoa continua sendo a mesma mesmo quando sua afiliação e função mudam. É melhor que o Linux login represente apenas uma identidade estável, enquanto permissões de administrador, desenvolvedor ou participante de projeto mudam separadamente por groups e RBAC.
Decidi manter OMZ, P10K e meus alias somente na conta humana. AI Cells e service accounts não lerão configurações do interactive shell; serão executados por systemd units fixas, EnvironmentFiles e caminhos absolutos. Um prompt bonito melhora minha produtividade, mas não tem relação com a estabilidade do serviço.
Ainda não criei todas essas contas às pressas. Primeiro defini nomes, propriedade dos arquivos, permissão de login e limites de acesso a sudo e Docker. Delimitar isso enquanto o servidor está vazio é muito mais simples do que separar tudo depois de misturado em uma única conta.
A fronteira do AI Cell chega a UID, HOME e OAuth
A maior mudança no meu entendimento desta vez foi sobre sistemas multiusuário.
Quando vemos apenas GUIs de desktop, parece que o usuário visível na tela de login ocupa o computador inteiro. No Linux, a tela de login visível e os usuários com processos em execução são conceitos diferentes. Vários usuários podem se conectar por SSH ao mesmo tempo, e processos de service accounts que não fizeram login podem continuar rodando sob o systemd.
Essa estrutura foi especialmente importante ao estender para Linux o modelo de AI Cell que eu havia redefinido por usuário do macOS. Um AI Cell não era apenas o nome de um processo.
1 AI Cell
= 1 conjunto de Linux UID e HOME
= 1 conjunto de OAuth e CODEX_HOME
= 1 conjunto de Gateway e Port
= 1 conjunto de Session, Memory e Workspace
= 1 conjunto de systemd unit e cgroup budget
Quando o Cell de cada pessoa tem UID e HOME próprios, autenticação, memória e espaço de trabalho se separam naturalmente. Cada Cell roda em um port ou Unix socket diferente, e o systemd o mantém ativo após o boot mesmo sem o usuário estar conectado por SSH. Vários Cells podem coexistir no mesmo servidor sem que o OAuth ou a Memory de um seja usado como fallback de outro.
Por outro lado, decidi não dar aos AI Cells sudo, mount completo do NAS, credenciais de administrador da DB de produção nem acesso ao Docker socket. A documentação oficial do Docker também alerta que o group docker concede privilégios de nível root.2 Adicionar contas humanas, de IA e de serviço a esse group por conveniência apagaria, na prática, as fronteiras que eu acabara de separar.
As operações do Docker serão feitas explicitamente por um administrador humano com sudo, ou por um helper restrito de propriedade do root e uma systemd unit que aceitem apenas operações predefinidas. A IA poderá coordenar um deploy, mas não terá diretamente um shell arbitrário nem todos os privilégios do Docker.
NAS como ingress, Linux como application Runtime
O servidor Linux não é dedicado apenas ao AI Orchestration. Web, API e DB do Operations Automation também deverão rodar nele em um Docker Runtime. Isso não significa colocar tudo em uma conta, um Compose project e uma network.
As conexões externas continuarão usando o HTTPS e o reverse proxy já administrados pelo NAS. O Linux executará as aplicações reais.
usuário externo
→ HTTPS 443
→ roteador da empresa
→ TLS e hostname reverse proxy do NAS
→ frontend Linux
→ API interna do Docker
→ DB interna do Docker
Não é necessário expor diretamente à Internet o port administrativo do NAS, o SSH do Linux nem os ports de API e DB. O NAS permanece como ingress que processa hostnames e certificados, além de ponto de storage e backup; o Linux assume o application Runtime. Não estou descartando o caminho HTTPS externo criado ao migrar a automação de férias para o NAS; apenas o backend final será movido para o servidor dedicado.
Também mantive separados o deploy de código e a importação de dados de RH do NAS.
código
→ verificar release e artifact hash
→ deploy helper restrito
→ health check e rollback
dados de RH
→ pasta read-only aprovada no NAS
→ staging, validation e preview
→ aprovação
→ DB transaction e audit
O AI Orchestration pode analisar uma mudança e solicitar aprovação. Mas o deploy real e a importação de dados serão realizados separadamente por um broker e um importer que aceitam apenas operações definidas. O MacBook pode ser usado para desenvolvimento, dry-run, conferência de previews e início de trabalhos aprovados, mas não será o ponto de canonical mutation da DB de produção.
O servidor Linux ainda não tem Docker nem application DB. Portanto, não o chamei de production backend só porque a reserva DHCP e o SSH funcionaram. O target do reverse proxy do NAS só poderá mudar depois de preparar o frontend port exato, health check, backup e restore, e rollback.
Um Codex Skill que preserva toda a topology da rede
A continuidade com a conversa seguinte era tão importante quanto a própria configuração do servidor.
Atualizei um Codex Skill dedicado à rede da empresa e seu inventário detalhado com as relações entre o roteador, os dois NAS, o Mac Runtime existente, o novo servidor Linux, o HTTPS externo e o SSH interno. Não é apenas uma lista de IPs: ele distingue a função de cada equipamento, o ponto de origem, os hops intermediários e o Runtime final de cada fluxo de traffic.
O Skill também não mistura fatos já concluídos com a estrutura futura.
- Instalação, reinicialização do Ubuntu e SSH interno estão concluídos.
- As identities multiusuário e os limites de permissão foram definidos, mas as contas ainda não foram criadas.
- Docker, AI Cells e Operations Automation ainda não foram implantados no Linux.
- O reverse proxy do NAS só será direcionado ao Linux depois que health e rollback estiverem prontos.
Agora, mesmo abrindo uma nova sessão do Codex, não preciso começar explicando “Qual era o IP do servidor?”, “O NAS executa a application?” ou “Por que o serviço SSH estava disabled?”. O Skill transmite em conjunto a topology real, os limites de segurança, o estado verificado e o estado ainda incompleto.
Assim, o servidor ainda não é um production server completo, mas também não é apenas um SSD vazio com Ubuntu instalado. O próximo trabalho é colocar contas humanas, AI Cells e o Operations Automation Runtime em funcionamento dentro dos limites já definidos.
Daqui em diante, sempre que instalar alguma coisa, acho que vou perguntar primeiro: “Com qual conta isso será executado?”, “Quais HOME e credenciais ela possuirá?” e “Quais ports e data flows serão permitidos?”. Mais do que montar um servidor, sinto que defini primeiro as regras que permitirão ampliá-lo sem quebrá-lo continuamente.
Referências
-
Uma socket unit do systemd pode monitorar um socket e ativar o serviço correspondente quando recebe incoming traffic. Manual oficial de systemd.socket ↩
-
O group
docker, que pode acessar o Unix socket do Docker daemon, concede privilégios de nível root. Etapas pós-instalação do Docker Engine no Linux ↩
Deixe um comentário