Pular para o conteúdo principal

Self-Hosting

O AISCouncil é um único arquivo HTML autocontido. Você pode hospedá-lo em qualquer servidor de arquivos estáticos, rodá-lo de um pen drive ou até abri-lo diretamente do seu sistema de arquivos. Sem backend, sem banco de dados, sem runtime -- apenas um arquivo.

O Método Mais Simples

Baixe index.html e abra-o em um navegador:

# É isso. Abra o arquivo.
open index.html # macOS
xdg-open index.html # Linux
start index.html # Windows

O app funciona imediatamente do protocolo file://. Todas as funcionalidades que não requerem HTTPS (tudo exceto instalação PWA e API de clipboard) funcionam normalmente.

dica

Para a experiência completa incluindo instalação PWA e acesso ao clipboard, sirva o arquivo via HTTPS usando qualquer servidor de arquivos estáticos.

Servidor de Arquivos Estáticos

Faça upload para qualquer servidor web. Sem configuração server-side necessária.

Python (teste local rápido)

python3 -m http.server 8000
# Abra http://localhost:8000

Caddy (HTTPS com certificados automáticos)

caddy file-server --root /path/to/aiscouncil --listen :8080

Nginx

server {
listen 443 ssl;
server_name aiscouncil.example.com;

ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;

root /var/www/aiscouncil;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}
}

Hospedagem em Cloud

O app funciona em qualquer plataforma de hospedagem estática com configuração zero:

PlataformaMétodo de Deploy
Cloudflare PagesConecte repo Git ou drag-and-drop
NetlifyConecte repo Git ou drag-and-drop
VercelConecte repo Git ou vercel deploy
GitHub PagesPush para branch gh-pages
AWS S3 + CloudFrontUpload de arquivos para S3, sirva via CloudFront
Firebase Hostingfirebase deploy

Arquivos Recomendados para Deploy

Embora apenas index.html seja estritamente necessário, deployar esses arquivos adicionais habilita funcionalidades PWA:

seu-servidor/
index.html # A aplicação completa (obrigatório)
sw.js # Service worker para suporte offline
manifest.webmanifest # Manifest PWA (nome, ícones, tema)
icon.svg # Ícone vetorial
icon-192.png # Ícone Android home screen
icon-512.png # Splash screen / ícone maskable
favicon.ico # Ícone de aba do navegador

Adições opcionais:

  s/
index.html # Editor web (se você quiser o editor também)
registry/
models.json # Registro de modelos local (se você quiser dados de modelos offline)
ads.json # Configuração de anúncios (apenas se usando o sistema de anúncios do nível gratuito)

Deploy com Docker

Um deploy Docker mínimo usando Nginx:

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
COPY sw.js /usr/share/nginx/html/
COPY manifest.webmanifest /usr/share/nginx/html/
COPY icon.svg /usr/share/nginx/html/
COPY icon-192.png /usr/share/nginx/html/
COPY icon-512.png /usr/share/nginx/html/
COPY favicon.ico /usr/share/nginx/html/
EXPOSE 80

Build e execute:

docker build -t aiscouncil .
docker run -d -p 8080:80 aiscouncil
# Abra http://localhost:8080

Para HTTPS com Docker, use um reverse proxy como Traefik ou Caddy na frente do container Nginx.

O Que Roda Localmente

Tudo. O arquivo HTML contém todo CSS, JavaScript e código de módulo inline. Quando um usuário abre a página:

  • A UI renderiza inteiramente client-side
  • Chaves de API são armazenadas no navegador do usuário (localStorage)
  • Histórico de chat e configs de bot são armazenados no navegador do usuário (IndexedDB)
  • Chamadas de API LLM vão diretamente do navegador para o provedor (Anthropic, OpenAI, xAI, etc.)
  • Nenhum dado passa pelo seu servidor

Seu servidor serve um arquivo estático. Esse é seu único trabalho.

Modo Convidado

Quando hospedado em um domínio customizado (não aiscouncil.net), o app opera em modo convidado:

  • Sem Google Sign-In necessário -- o portão de login é pulado
  • Todas as funcionalidades funcionam sem autenticação
  • Usuários vão diretamente para a interface de chat
  • Configurações, armazenamento e todas as funcionalidades estão totalmente funcionais
informação

Modo convidado ativa automaticamente quando o app detecta que está rodando em localhost, um domínio .pages.dev ou qualquer domínio diferente de aiscouncil.net. Sem configuração necessária.

Base de API Customizada

Por padrão, o app envia requisições de auth, billing e rastreamento de uso para https://api.aiscouncil.net/v1. Para deploys self-hosted, você pode sobrescrever isso:

localStorage.setItem("ais-api-base", "https://sua-api.exemplo.com/v1");

Isso é opcional. Se você não está usando as funcionalidades de billing/auth gerenciadas, o app funciona sem qualquer base de API -- todas as chamadas LLM vão diretamente do navegador para o provedor.

Proxy Local (aiscouncil-serve)

Se você quer evitar expor chaves de API no navegador (ex: em um ambiente de escritório compartilhado), você pode rodar o proxy local aiscouncil-serve:

ANTHROPIC_API_KEY=sk-ant-... \
OPENAI_API_KEY=sk-... \
XAI_API_KEY=xai-... \
./aiscouncil-serve --port 8741

O proxy roteia requisições por prefixo de modelo para o provedor correto:

Prefixo de ModeloProvedorAuth
claude-*Anthropicheader x-api-key
gpt-*, o1*, o3*OpenAIBearer token
grok-*xAIBearer token
meta-llama/, deepseek/, qwen/, mistralai/, google/OpenRouterBearer token
Todo o restoOllama (localhost)Nenhum

O proxy também suporta header X-Provider para forçar um provedor específico independentemente do prefixo de modelo.

Build a partir do fonte:

cd serve
../tools/zig/zig build -Doptimize=ReleaseSmall
# Binário em: zig-out/bin/aiscouncil-serve (~2.3 MB)

Deploy Offline

Para ambientes air-gapped:

  1. Faça deploy dos arquivos para um servidor web interno
  2. Na primeira visita, o service worker cacheia tudo
  3. Após cacheamento, o app funciona sem qualquer acesso à rede
  4. Usuários podem conversar com Ollama ou qualquer LLM local rodando na mesma rede

Pré-carregue o registro de modelos colocando registry/models.json junto ao index.html. O app verifica por uma cópia local antes de tentar buscar do GitHub.

Considerações CORS

Ao usar servidores de inferência locais (Ollama, vLLM, etc.), o navegador impõe CORS (Cross-Origin Resource Sharing). Seu servidor de inferência deve permitir requisições da sua origem de hospedagem.

Ollama:

# Defina antes de iniciar o Ollama
OLLAMA_ORIGINS=* ollama serve

vLLM:

vllm serve nome-do-modelo --allowed-origins '*'

Geral (qualquer servidor atrás de Nginx):

add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Access-Control-Allow-Methods' 'POST, OPTIONS' always;
aviso

Usar * para Access-Control-Allow-Origin é bom para desenvolvimento local, mas deve ser restrito à sua origem específica em deploys de produção.

Compilando do Fonte

Para modificar o app e recompilar:

# Clone o repositório
git clone https://github.com/nicholasgasior/aiscouncil.net.git
cd aiscouncil.net

# Edite arquivos fonte em src/ (NÃO index.html diretamente)
# O app é dividido em ~35 arquivos fonte que são concatenados

# Compile o output de arquivo único
./build.sh

# Verifique se o build corresponde
./build.sh --check

O processo de build concatena todos os arquivos src/ em ordem em um único index.html. Sem bundler, sem transpiler, sem npm -- apenas concatenação shell.

Editor Web

Para também hospedar o editor web, inclua o diretório s/:

seu-servidor/
index.html # Plataforma de bots
s/
index.html # Editor web (aiscouncil.net/s/)

O editor usa o mesmo codec de compressão mas com prefixo de versão A em vez de B. É um arquivo HTML autocontido separado com seu próprio conjunto de funcionalidades (edição WYSIWYG, suporte multi-formato, algoritmos de compressão).

Portabilidade de Dados

Usuários podem exportar todos seus dados via Settings > Privacy > Export All Data. O export é um arquivo JSON contendo todos os perfis de bot, históricos de chat e configurações. Chaves de API são excluídas dos exports. O export pode ser importado em qualquer outra instância do AISCouncil.

Isso significa que usuários nunca ficam bloqueados em um deploy específico. Eles podem mover entre instâncias self-hosted, o site oficial ou qualquer outro host a qualquer momento.