panel-api
Backend API панели
Backend API живёт в репозитории duck-obsidian:
/home/supervisor/leonid_projects/duck-obsidian/.deploy/api
Он слушает:
127.0.0.1:3017
Панель duck-obsidian-panel ходит в него через Nginx /api/*.
Зачем нужен API
Браузер не должен запускать shell-команды напрямую.
Поэтому схема такая:
browser UI
-> nginx /api/*
-> backend API 127.0.0.1:3017
-> gardenctl/systemctl/docker/nginx/certbot
Env-файл
/etc/duck-garden-panel.env
Пример:
PORT=3017
DUCK_PANEL_TOKEN=long-random-token
DUCK_RUNNER_DIR=/home/supervisor/leonid_projects/duck-obsidian/.deploy
DUCK_GARDENS_BASE_DIR=/home/supervisor/leonid_projects/obsidians
DUCK_GARDEN_DOMAIN_ROOT=obsidians.otc.guru
DUCK_GARDEN_GITHUB_OWNER=leo-mmmmmmm
DUCK_GARDEN_ENGINE_VERSION=1.0.18
DUCK_GARDEN_PORT_START=8089
DUCK_GARDEN_PORT_END=8999
DUCK_CERTBOT_EMAIL=leo.mikhaylov.2000@gmail.com
DUCK_GARDEN_AUTO_HTTPS=true
DUCK_GITHUB_TOKEN=
Проверить service
sudo systemctl status duck-garden-panel-api --no-pager
sudo journalctl -u duck-garden-panel-api -n 100 --no-pager
Перезапустить:
sudo systemctl restart duck-garden-panel-api
Healthcheck
curl -s http://127.0.0.1:3017/health
Ожидаемо:
{"ok":true}
Авторизованный запрос
TOKEN="$(sudo awk -F= '$1=="DUCK_PANEL_TOKEN"{print $2}' /etc/duck-garden-panel.env)"
curl -s \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:3017/api/gardens
Основные endpoints
GET /api/gardens
POST /api/gardens
PATCH /api/gardens/:slug
POST /api/gardens/:slug/enable
POST /api/gardens/:slug/disable
POST /api/gardens/:slug/rebuild
POST /api/gardens/:slug/https
DELETE /api/gardens/:slug
GET /api/system/doctor
GET /health
Access-control endpoints:
GET /api/gardens/:slug/access
PATCH /api/gardens/:slug/access
POST /api/gardens/:slug/access/users
POST /api/gardens/:slug/access/users/:userId/password
PATCH /api/gardens/:slug/access/users/:userId
DELETE /api/gardens/:slug/access/users/:userId
GitHub repo check:
GET /api/github/repos/:owner/:repo
Что делает POST /api/gardens
Payload:
{
"name": "Test Garden",
"slug": "test-garden",
"repoName": "test-garden",
"accentColor": "#f5c542"
}
API:
1. Валидирует slug и accentColor.
2. Выбирает свободный port из диапазона.
3. При наличии DUCK_GITHUB_TOKEN создаёт GitHub repo, если его нет.
4. Запускает gardenctl create.
5. Сохраняет garden в catalog.
6. Если переданы name/accentColor/logoSvg, обновляет garden.config.json и запускает rebuild.
Где хранится catalog
/home/supervisor/leonid_projects/obsidians/.catalog/gardens.json
/home/supervisor/leonid_projects/obsidians/.catalog/access.json
Если catalog пустой, API умеет собрать список gardens из файловой системы в /home/supervisor/leonid_projects/obsidians.
Enable / disable
Enable:
POST /api/gardens/:slug/enable
Делает:
sudo systemctl enable --now <slug>-pull.timer
docker compose up -d caddy
Disable:
POST /api/gardens/:slug/disable
Делает:
sudo systemctl disable --now <slug>-pull.timer
docker compose stop caddy
Rebuild
POST /api/gardens/:slug/rebuild
Делает:
cd /home/supervisor/leonid_projects/duck-obsidian/.deploy
./gardenctl rebuild <slug>
HTTPS
POST /api/gardens/:slug/https
Делает:
sudo certbot --nginx -d <domain> --non-interactive --agree-tos
Частые проблемы
DUCK_PANEL_TOKEN is not set on server
В /etc/duck-garden-panel.env не задан DUCK_PANEL_TOKEN или service не перечитал env.
sudo systemctl restart duck-garden-panel-api
sudo journalctl -u duck-garden-panel-api -n 100 --no-pager
401 Unauthorized
Nginx не прокинул правильный Bearer token.
Проверить token напрямую:
TOKEN="$(sudo awk -F= '$1=="DUCK_PANEL_TOKEN"{print $2}' /etc/duck-garden-panel.env)"
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:3017/api/gardens
Если напрямую работает, проверять nginx config панели.
Нет свободных ports
API ищет свободный port в диапазоне:
DUCK_GARDEN_PORT_START=8089
DUCK_GARDEN_PORT_END=8999
Проверить занятые порты:
sudo ss -ltnp