--- name: easypanel-api description: Referência completa da API tRPC oficial do EasyPanel — todos os endpoints para projectos, serviços, deploy e configurações. --- # /easypanel-api - API Oficial EasyPanel Referência da API tRPC do EasyPanel. Baseado em engenharia reversa do SDK oficial. --- ## Autenticação ```bash TOKEN=$(cat /etc/easypanel/.api-token) # Header obrigatório em todos os pedidos: -H "Authorization: Bearer $TOKEN" ``` **Base URL:** `http://localhost:3000/api/trpc/` Usar sempre via SSH localhost. Nunca expor externamente. --- ## Formato de Pedidos | Método | Quando usar | Formato | |--------|-------------|---------| | GET | Leitura (list, inspect, get) | `?input=URL_ENCODED_JSON` | | POST | Escrita (create, update, deploy, destroy) | `-d '{"json":{...}}'` com `Content-Type: application/json` | ```bash # GET curl -s "http://localhost:3000/api/trpc/ENDPOINT?input=URL_ENCODED_JSON" \ -H "Authorization: Bearer $TOKEN" # POST curl -s -X POST "http://localhost:3000/api/trpc/ENDPOINT" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"json":{...}}' ``` --- ## Projects API | Endpoint | Tipo | Descrição | |----------|------|-----------| | `projects.listProjects` | GET | Listar todos os projectos | | `projects.listProjectsAndServices` | GET | Projectos + todos os serviços | | `projects.createProject` | POST | Criar projecto (`name`) | | `projects.destroyProject` | POST | Destruir projecto (`projectName`) | | `projects.inspectProject` | GET | Inspecionar projecto (`projectName`) | ```bash # Listar projectos (teste rápido de autenticação) curl -s "http://localhost:3000/api/trpc/projects.listProjects" \ -H "Authorization: Bearer $TOKEN" # Criar projecto curl -s -X POST "http://localhost:3000/api/trpc/projects.createProject" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"json":{"name":"novo-projecto"}}' ``` --- ## Services API Endpoints completos com exemplos curl: ver [references/services-api.md](references/services-api.md) | Endpoint | Tipo | Descrição | |----------|------|-----------| | `services.app.createService` | POST | Criar serviço app | | `services.postgres.createService` | POST | Criar PostgreSQL | | `services.mysql.createService` | POST | Criar MySQL | | `services.redis.createService` | POST | Criar Redis | | `services.app.inspectService` | GET | Inspecionar serviço | | `services.app.deployService` | POST | Fazer deploy | | `services.app.enableService` | POST | Activar serviço | | `services.app.disableService` | POST | Desactivar serviço | | `services.app.destroyService` | POST | Destruir serviço | **Parâmetros obrigatórios:** `projectName` + `serviceName` em todos os endpoints de serviços. **Regra Descomplicar:** `projectName:"descomplicar"` para serviços próprios. --- ## Service Configuration API Endpoints completos com exemplos curl: ver [references/service-config-api.md](references/service-config-api.md) | Endpoint | Descrição | |----------|-----------| | `services.app.updateSourceGithub` | Source GitHub (`owner`, `repo`, `ref`, `path`) | | `services.app.updateSourceGit` | Source Git custom (`repo`, `ref`, `path`) | | `services.app.updateSourceImage` | Source Docker image (`image`) | | `services.app.updateEnv` | Variáveis de ambiente (`env` como string multi-linha) | | `services.app.updateDomains` | Domínios (`domains[]` com `host`, `https`, `port`) | | `services.app.updateMounts` | Volumes (`mounts[]` com `type`, `name`, `mountPath`) | | `services.app.updatePorts` | Portas TCP/UDP (`ports[]` com `published`, `target`, `protocol`) | | `services.app.updateResources` | CPU/RAM (`memoryLimit`, `cpuLimit`, etc.) | | `services.app.updateBuild` | Build config (`type`, `buildCommand`, `startCommand`) | | `services.app.updateAdvanced` | Deploy avançado (`replicas`, `command`, `zeroDowntime`) | | `services.postgres.updateBackup` | Backup BD para S3 | --- ## Monitor API ```bash # Stats do sistema curl -s "http://localhost:3000/api/trpc/monitor.getSystemStats" \ -H "Authorization: Bearer $TOKEN" # Stats de serviço (URL encode necessário) # input: {"json":{"projectName":"descomplicar","serviceName":"api"}} curl -s "http://localhost:3000/api/trpc/monitor.getServiceStats?input=..." \ -H "Authorization: Bearer $TOKEN" # Stats Docker tasks curl -s "http://localhost:3000/api/trpc/monitor.getDockerTaskStats" \ -H "Authorization: Bearer $TOKEN" ``` --- ## Logs API ```bash # Logs de serviço (tail=100) # input: {"json":{"projectName":"descomplicar","serviceName":"api","tail":100}} curl -s "http://localhost:3000/api/trpc/logs.getServiceLogs?input=..." \ -H "Authorization: Bearer $TOKEN" ``` --- ## Settings API | Endpoint | Tipo | Descrição | |----------|------|-----------| | `settings.getServerIp` | GET | IP do servidor | | `settings.getPanelDomain` | GET | Domínio do painel | | `settings.setPanelDomain` | POST | Definir domínio (`domain`) | | `settings.getLetsEncryptEmail` | GET | Email Let's Encrypt | | `settings.setLetsEncryptEmail` | POST | Definir email (`email`) | | `settings.restartTraefik` | POST | Reiniciar Traefik | | `settings.restartEasypanel` | POST | Reiniciar EasyPanel | | `settings.pruneDockerImages` | POST | Limpar imagens Docker | --- ## URL Encoding para GET ```bash INPUT='{"json":{"projectName":"descomplicar","serviceName":"api"}}' ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$INPUT'))") curl -s "http://localhost:3000/api/trpc/services.app.inspectService?input=$ENCODED" \ -H "Authorization: Bearer $TOKEN" ``` --- ## Wrapper Script Criar `/usr/local/bin/easypanel-api`: ```bash #!/bin/bash TOKEN=$(cat /etc/easypanel/.api-token) BASE="http://localhost:3000/api/trpc" if [ -z "$2" ]; then curl -s "$BASE/$1" -H "Authorization: Bearer $TOKEN" else curl -s -X POST "$BASE/$1" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "$2" fi ``` Uso: `easypanel-api projects.listProjects` --- ## Checklist de Uso - [ ] SSH para servidor `easy` - [ ] `TOKEN=$(cat /etc/easypanel/.api-token)` - [ ] Testar: `curl -s ".../projects.listProjects" -H "Authorization: Bearer $TOKEN"` - [ ] Usar endpoints conforme documentado - [ ] Validar resposta em `result.data.json` --- ## Limitações de Mounts O EasyPanel usa Docker Swarm internamente. Isto impõe limitações nos mounts que diferem do Docker standalone. ### Tipos de mount suportados | Tipo | API `type` | Comportamento | Limitações | |------|-----------|---------------|------------| | **Volume mount** | `volume` | Volume gerido pelo Docker Swarm | Funciona bem. Dados persistem no nó. Sem acesso directo ao filesystem do host | | **Bind mount** | `bind` | Monta directório do host no container | **Limitado no Swarm** — só funciona se o serviço estiver fixo a um nó específico | | **File mount** | `file` | Monta ficheiro individual (config) | Funciona. Ideal para ficheiros de configuração | ### Limitações críticas 1. **Bind mounts no Swarm** — O Docker Swarm não garante que o container corra sempre no mesmo nó. Um bind mount (`type: "bind"`) aponta para um path no host, mas se o container migrar para outro nó, esse path pode não existir. O EasyPanel mitiga isto parcialmente por correr num único nó, mas a limitação arquitectural mantém-se. 2. **Sem suporte nativo a NFS/CIFS** — A API `updateMounts` não suporta drivers de volume remotos (NFS, CIFS, etc.) directamente. Para volumes partilhados, é necessário criar o volume Docker manualmente com o driver adequado e depois referenciá-lo. 3. **Permissões** — Volumes criados via API pertencem a `root:root` por defeito. Containers que correm com utilizador não-root podem ter problemas de permissões. Workaround: usar `command` no `updateAdvanced` para corrigir permissões no arranque. 4. **Substituição total** — `updateMounts` substitui **todos** os mounts existentes. Para adicionar um mount, é preciso primeiro obter os mounts actuais via `inspectService` e enviar a lista completa com o novo mount incluído. ### Workarounds conhecidos ```bash # 1. Obter mounts actuais antes de adicionar novo INSPECT=$(curl -s "http://localhost:3000/api/trpc/services.app.inspectService?input=..." \ -H "Authorization: Bearer $TOKEN") # Extrair mounts existentes do JSON e adicionar o novo # 2. Volume com permissões corrigidas — usar initCommand curl -s -X POST "http://localhost:3000/api/trpc/services.app.updateAdvanced" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"json":{ "projectName":"descomplicar", "serviceName":"minha-api", "deploy":{ "command":"chown -R 1000:1000 /app/data && node dist/index.js" } }}' # 3. Volume Docker manual com driver NFS (fora da API) docker volume create --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.10,rw \ --opt device=:/export/data \ vol-nfs-data # Depois referenciar na API: # {"type":"volume","name":"vol-nfs-data","mountPath":"/app/data"} ``` ### Recomendações - **Preferir `volume`** sobre `bind` — mais portável e compatível com Swarm - **Usar `file`** para configs individuais (nginx.conf, .env, etc.) - **Inspeccionar antes de actualizar** — a API substitui a lista inteira de mounts - **Documentar volumes manuais** — volumes criados fora da API não aparecem no painel EasyPanel até serem referenciados por um serviço --- ## Anti-Patterns | Anti-Pattern | Risco | Alternativa | |--------------|-------|-------------| | Expor API externamente | Segurança crítica | Usar apenas via SSH localhost | | Hardcode token | Leak de credenciais | Usar `/etc/easypanel/.api-token` | | Não validar response | Erros silenciosos | Verificar `result.data.json` | | POST sem `Content-Type` | Request falha | Sempre incluir header | --- ## Ficheiros de Referência | Ficheiro | Conteúdo | |----------|----------| | [references/services-api.md](references/services-api.md) | Endpoints de serviços com curl completo (create, inspect, deploy, enable/disable, destroy) | | [references/service-config-api.md](references/service-config-api.md) | Endpoints de configuração (source, env, domains, mounts, ports, resources, build, deploy, backup BD) |