# Kraken — Portainer Access & Cloudflared SSH Tunnel > Статус: ⏳ cloudflared pending — ждём CF Tunnel token от Alex ## Portainer | Параметр | Значение | |---|---| | URL | `http://localhost:9000` | | Auth header | `X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=` | | Endpoint ID | уточнить через `GET /api/endpoints` (обычно `1` для local Docker) | ### Portainer API — Quick Reference ```bash BASE=http://localhost:9000 KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" EP=1 # endpoint ID # Список endpoints (узнать EP) curl -s -H "X-API-Key: $KEY" $BASE/api/endpoints | jq '[.[].Id]' # Список контейнеров 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 -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \ "$BASE/api/endpoints/$EP/docker/containers/create?name=" \ -d '' # Запустить контейнер curl -s -X POST -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers//start" # Логи curl -s -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers//logs?stdout=1&stderr=1&tail=50" # Удалить контейнер curl -s -X DELETE -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers/" ``` ### Временный Alpine-контейнер (запустить команду на хосте) Для разовых задач (записать файл, проверить путь и т.д.) — alpine с bind `/:/host`: ```bash BASE=http://localhost:9000 KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" EP=1 # 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", "echo hello from host > /host/tmp/test.txt && echo DONE"], "HostConfig": { "Binds": ["/:/host"], "AutoRemove": false } }' | jq -r '.Id') # 2. Запустить curl -s -X POST -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers/$ID/start" # 3. Подождать завершения (1-2 сек) и забрать логи sleep 2 curl -s -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers/$ID/logs?stdout=1&stderr=1" # 4. Удалить curl -s -X DELETE -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers/$ID" ``` > ⚠️ `AutoRemove: false` — обязательно, иначе контейнер удалится до того как получишь логи > ⚠️ Используй `alpine`, не `alpine/git` и подобные — у них есть ENTRYPOINT, `sh -c` не сработает --- ## Cloudflared — деплой ### Шаг 1 — Получить CF Tunnel token (делает Alex вручную) 1. Открыть [Cloudflare Zero Trust → Networks → Tunnels](https://one.dash.cloudflare.com/) 2. **Create a tunnel** → Cloudflared → назвать `kraken` 3. На шаге "Install connector": скопировать команду вида: ``` cloudflared service install eyJ... ``` Нас интересует только токен — длинная строка после `service install` 4. Сохранить токен — вписать в эту заметку ниже **CF Tunnel Token:** ``` <ВСТАВИТЬ СЮДА ТОКЕН ПОСЛЕ СОЗДАНИЯ ТОННЕЛЯ> ``` ### Шаг 2 — Создать docker-compose.yml через alpine Используем alpine-контейнер с bind `/:/host` для записи файла: ```bash BASE=http://localhost:9000 KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" EP=1 TOKEN="" COMPOSE_B64=$(echo "services: cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: unless-stopped command: [\"tunnel\", \"--no-autoupdate\", \"run\"] environment: - TUNNEL_TOKEN=${TOKEN} network_mode: host" | base64 | tr -d '\n') ID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \ "$BASE/api/endpoints/$EP/docker/containers/create?name=alpine-setup-$$" \ -d "{ \"Image\": \"alpine\", \"Cmd\": [\"sh\", \"-c\", \"mkdir -p /host/home/kraken/cloudflared && echo ${COMPOSE_B64} | base64 -d > /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" ``` ### Шаг 3 — Поднять cloudflared контейнер через Portainer API ```bash BASE=http://localhost:9000 KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" EP=1 TOKEN="" # Создать контейнер 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') # Запустить curl -s -X POST -H "X-API-Key: $KEY" \ "$BASE/api/endpoints/$EP/docker/containers/$CID/start" echo "Container ID: $CID" ``` ### Шаг 4 — Проверить логи ```bash 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?all=true" | 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" ``` Ожидаем в логах: ``` INF Registered tunnel connection connIndex=0 ... protocol=http2 INF Connection ... registered connIndex=0 INF Connection ... registered connIndex=1 ... ``` Если видишь все 4 соединения — туннель активен. ### Шаг 5 — Обновить статус в этой заметке Заменить `⏳ cloudflared pending` в заголовке на `✅ cloudflared запущен`. --- ## Что делает Alex после запуска (вручную в CF Zero Trust) После того как cloudflared запущен и туннель появился как **Active** в Zero Trust: 1. Открыть туннель `kraken` → **Edit** → вкладка **Public Hostname** → **Add a public hostname** 2. Добавить поддомен SSH: - Subdomain: `ssh` - Domain: `kraken.qentra.top` (создать заранее в DNS) - Service type: **SSH** - URL: `localhost:22` 3. Сохранить — DNS запись создаётся автоматически Повторить для других сервисов если нужно: - `omv.kraken.qentra.top` → HTTP → `localhost:80` (OMV Web UI) - `portainer.kraken.qentra.top` → HTTP → `localhost:9000` > ⚠️ Аналогично тому как настраивался `zulip.qentra.top` на Eagle: > токен получается при создании тоннеля в Zero Trust → вставляется в `TUNNEL_TOKEN` --- ## SSH-доступ через Cloudflare Tunnel (с Eagle) После настройки поддомена добавить в `~/.ssh/config` на Eagle: ``` Host ssh.kraken.qentra.top ProxyCommand cloudflared access ssh --hostname %h User kraken IdentityFile ~/.ssh/id_rsa StrictHostKeyChecking no ``` Затем: ```bash ssh ssh.kraken.qentra.top ``` > `cloudflared` на Eagle уже есть (используется для `zulip.qentra.top`) --- ## Связанные заметки - [[openmediavault-rpi5]] — настройка Kraken (Docker, Hermes, структура папок) - [[truenas-infrastructure]] — Taiga (аналогичный Portainer API подход) - [[obsidian-sync]] — синхронизация vault