Files
obsidian-vault/family/how-to/kraken-portainer-access.md
T

12 KiB
Raw Blame History

Статус: cloudflared запущен (прямой токен)

Portainer

Параметр Значение
URL http://localhost:9000
Auth header X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=
Endpoint ID уточнить: `curl -s -H "X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" http://localhost:9000/api/endpoints

Portainer API — Quick Reference

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1

# Список контейнеров
curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json?all=true" \
  | jq '[.[] | {name: .Names[0], status: .Status, image: .Image}]'

# Логи контейнера
curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/<ID>/logs?stdout=1&stderr=1&tail=50"

# Удалить контейнер
curl -s -X DELETE -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/<ID>"

Временный Alpine-контейнер (выполнить команду на хосте)

Для разовых задач — alpine с bind /:/host:

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1

ID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  "$BASE/api/endpoints/$EP/docker/containers/create?name=alpine-tmp-$$" \
  -d '{
    "Image": "alpine",
    "Cmd": ["sh", "-c", "YOUR_COMMAND_HERE && echo DONE"],
    "HostConfig": {"Binds": ["/:/host"], "AutoRemove": false}
  }' | jq -r '.Id')

curl -s -X POST -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID/start"
sleep 2
curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID/logs?stdout=1&stderr=1"
curl -s -X DELETE -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID"

⚠️ AutoRemove: false — обязательно, иначе контейнер удалится до получения логов ⚠️ Использовать alpine, не alpine/git — у git-образа свой ENTRYPOINT


Cloudflared — деплой (выполняет Кракен)

CF Tunnel уже создан Alex'ом (kraken в Zero Trust), ingress настроен. ⚠️ Актуальные маршруты (2026-09-04): kraken.qentra.top → HTTP localhost:8642 (Hermes API, НЕ SSH) и отдельный ssh-kraken.qentra.topssh://localhost:22 (published SSH application route; вход ssh kraken@ssh-kraken.qentra.top, работает с 2026-09-04). Полная картина и статус — kraken-access.

CF Tunnel Token:

eyJhIjoiZjE...TnpFNU5USTNNREl4WkRVeCJ9

Шаг 1 — Убедиться что EP = 1

curl -s -H "X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" \
  http://localhost:9000/api/endpoints | jq '[.[].Id]'

Если не 1 — запомнить реальный ID и использовать его вместо 1 в шагах ниже.

Шаг 2 — Создать и запустить cloudflared контейнер

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1
TOKEN="eyJhIjoiZjE0YTM3NWQ3NmU1ZTU4M2IzNjZhMDJhYjUyNDZiNDciLCJ0IjoiMmRkZDJiMjgtNjYwYy00NjQ0LTk1Y2ItY2Y1ZTQzNTBhMTA1IiwicyI6Ik5HVTRZalZtTURVdFptSm1OeTAwWVdGakxUaGlaamd0WmpFMFlUazVOekt3WTJWaCJ9"

CID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  "$BASE/api/endpoints/$EP/docker/containers/create?name=cloudflared" \
  -d "{
    \"Image\": \"cloudflare/cloudflared:latest\",
    \"Cmd\": [\"tunnel\", \"--no-autoupdate\", \"run\"],
    \"Env\": [\"TUNNEL_TOKEN=$TOKEN\"],
    \"HostConfig\": {
      \"RestartPolicy\": {\"Name\": \"unless-stopped\"},
      \"NetworkMode\": \"host\"
    }
  }" | jq -r '.Id')

echo "Container ID: $CID"

curl -s -X POST -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$CID/start"

echo "Started."

Шаг 3 — Проверить логи

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1

CID=$(curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/json" \
  | jq -r '.[] | select(.Names[] | contains("cloudflared")) | .Id')

curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$CID/logs?stdout=1&stderr=1&tail=30" \
  | strings

Ожидаем:

INF Registered tunnel connection connIndex=0 ... protocol=http2
INF Registered tunnel connection connIndex=1 ...
INF Registered tunnel connection connIndex=2 ...
INF Registered tunnel connection connIndex=3 ...

Все 4 соединения = туннель активен. Если видишь ERR — проверить токен.

Шаг 4 — Сохранить compose-файл (опционально, для удобства в будущем)

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1
TOKEN="eyJhIjoiZjE0YTM3NWQ3NmU1ZTU4M2IzNjZhMDJhYjUyNDZiNDciLCJ0IjoiMmRkZDJiMjgtNjYwYy00NjQ0LTk1Y2ItY2Y1ZTQzNTBhMTA1IiwicyI6Ik5HVTRZalZtTURVdFptSm1OeTAwWVdGakxUaGlaamd0WmpFMFlUazVOekt3WTJWaCJ9"

COMPOSE="services:\n  cloudflared:\n    image: cloudflare/cloudflared:latest\n    container_name: cloudflared\n    restart: unless-stopped\n    command: [\"tunnel\", \"--no-autoupdate\", \"run\"]\n    environment:\n      - TUNNEL_TOKEN=$TOKEN\n    network_mode: host"

ID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  "$BASE/api/endpoints/$EP/docker/containers/create?name=alpine-cf-setup" \
  -d "{
    \"Image\": \"alpine\",
    \"Cmd\": [\"sh\", \"-c\", \"mkdir -p /host/home/kraken/cloudflared && printf '$COMPOSE' > /host/home/kraken/cloudflared/docker-compose.yml && echo DONE\"],
    \"HostConfig\": {\"Binds\": [\"/:/host\"], \"AutoRemove\": false}
  }" | jq -r '.Id')

curl -s -X POST -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID/start"
sleep 2
curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID/logs?stdout=1&stderr=1"
curl -s -X DELETE -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$ID"

Шаг 5 — Создать скилл по внешнему доступу

mkdir -p /opt/data/skills/devops/kraken-external-access
cat > /opt/data/skills/devops/kraken-external-access/SKILL.md << 'SKILLEOF'
---
name: kraken-external-access
category: devops
description: Внешний доступ к Kraken через Cloudflare Tunnel — SSH с Eagle, Portainer API, управление cloudflared.
triggers:
  - "доступ к кракену снаружи"
  - "ssh к кракену с орла"
  - "управление docker на кракене удалённо"
  - "cloudflared крякен"
---

# Kraken — External Access via Cloudflare Tunnel

## SSH с Eagle (уже настроено в ~/.ssh/config на Eagle)

```bash
ssh kraken.qentra.top

Portainer API

BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=1

# Список контейнеров
curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json?all=true" \
  | jq '[.[] | {name: .Names[0], status: .Status}]'

Управление cloudflared

# Статус + логи
CID=$(curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json" \
  | jq -r '.[] | select(.Names[] | contains("cloudflared")) | .Id')
curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$CID/logs?stdout=1&stderr=1&tail=30" | strings

# Рестарт
curl -s -X POST -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$CID/restart"

Питфолы

  • network_mode: host — cloudflared видит все локальные порты Кракена напрямую
  • restart: unless-stopped — при падении поднимается автоматически
  • Токен в env TUNNEL_TOKEN — не менять без пересоздания контейнера
  • Статус туннеля: https://one.dash.cloudflare.com/ → Networks → Tunnels → kraken
  • Если туннель не поднимается — искать ERR в логах cloudflared

Связанные заметки

  • family/how-to/kraken-portainer-access.md — полная инструкция по деплою
  • family/how-to/openmediavault-rpi5.md — структура Docker на Кракене SKILLEOF echo "Скилл создан."

> ⚠️ `/opt/data/` — HDD-volume, скилл переживёт rebuild образа


### Временный запуск cloudflared с прямым токеном (только для диагностики)

**Внимание:** Этот метод передает токен напрямую в `Cmd` контейнера. Это **небезопасно** для постоянного использования, но использовался для устранения проблем с монтированием файлов `credentials.json` и `config.yaml`.

Контейнер `cloudflared-access-debug-direct-token` с ID `8d9b3f7cec6fe6e1622f3a4c920733e9c322dfc936165b005bc22a0348c489a4` запущен с прямым токеном.

```bash
BASE=http://localhost:9000
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
EP=3
TOKEN="eyJhIjoiZjE0YTM3NWQ3NmU1ZTU4M2IzNjZhMDJhYjUyNDZiNDciLCJ0IjoiMGVlNWIxNmQtYTNmMC00ZjEzLWJjMzQtMmE4ODFhMGE0NDBhIiwicyI6Ik5qYzNZekV5T1dNdE56TTFOUzAwWkdVM0xUa3dNakl0TnpFNU5USTNNREl4WkRVeCJ9" # Временный токен

CID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  "$BASE/api/endpoints/$EP/docker/containers/create?name=cloudflared-access-debug-direct-token" \
  -d "{\"Image\": \"cloudflare/cloudflared:latest\", \"Cmd\": [\"tunnel\", \"run\", \"--token\", \"$TOKEN\"], \"HostConfig\": {\"RestartPolicy\": {\"Name\":\"unless-stopped\"}, \"NetworkMode\":\"host\"}}" | jq -r '.Id')

curl -s -X POST -H "X-API-Key: $KEY" \
  "$BASE/api/endpoints/$EP/docker/containers/$CID/start"

Заменить первую строку > Статус: ⏳ cloudflared pending deploy на > Статус: ✅ cloudflared запущен (прямой токен).


SSH-доступ с Eagle

Reverse SSH tunnel через VPS (порт 2223). Работает без CF Access Application.

~/.ssh/config на Eagle:

Host kraken.qentra.top
  HostName 91.207.28.205
  Port 2223
  User kraken
  IdentityFile ~/.ssh/id_rsa
  StrictHostKeyChecking no

Подключение: ssh kraken.qentra.top

Как это работает

Кракен держит постоянный reverse SSH tunnel на VPS 91.207.28.205:

  • systemd-сервис kraken-tunnel.service (autossh, autostart, restart always)
  • VPS слушает порт 2223 → перенаправляет на localhost:22 Кракена
  • Ключ: /home/kraken/.ssh/id_ed25519

Управление туннелем на Кракене:

sudo systemctl status kraken-tunnel
sudo systemctl restart kraken-tunnel
sudo journalctl -u kraken-tunnel -n 20

Проверить порт на VPS:

ssh root@91.207.28.205 "ss -tlnp | grep 2223"

Связанные заметки