[2026-05-13] kraken-portainer-access: fix hostname, fill token, simplify steps
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Kraken — Portainer Access & Cloudflared SSH Tunnel
|
# Kraken — Portainer Access & Cloudflared SSH Tunnel
|
||||||
|
|
||||||
> Статус: ⏳ cloudflared pending — ждём CF Tunnel token от Alex
|
> Статус: ⏳ cloudflared pending deploy
|
||||||
|
|
||||||
## Portainer
|
## Portainer
|
||||||
|
|
||||||
@@ -8,31 +8,20 @@
|
|||||||
|---|---|
|
|---|---|
|
||||||
| URL | `http://localhost:9000` |
|
| URL | `http://localhost:9000` |
|
||||||
| Auth header | `X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=` |
|
| Auth header | `X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=` |
|
||||||
| Endpoint ID | уточнить через `GET /api/endpoints` (обычно `1` для local Docker) |
|
| Endpoint ID | уточнить: `curl -s -H "X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" http://localhost:9000/api/endpoints | jq '[.[].Id]'` (обычно `1`) |
|
||||||
|
|
||||||
### Portainer API — Quick Reference
|
### Portainer API — Quick Reference
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:9000
|
BASE=http://localhost:9000
|
||||||
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
||||||
EP=1 # endpoint ID
|
EP=1
|
||||||
|
|
||||||
# Список 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 -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=<NAME>" \
|
|
||||||
-d '<JSON>'
|
|
||||||
|
|
||||||
# Запустить контейнер
|
|
||||||
curl -s -X POST -H "X-API-Key: $KEY" \
|
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/<ID>/start"
|
|
||||||
|
|
||||||
# Логи
|
|
||||||
curl -s -H "X-API-Key: $KEY" \
|
curl -s -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/<ID>/logs?stdout=1&stderr=1&tail=50"
|
"$BASE/api/endpoints/$EP/docker/containers/<ID>/logs?stdout=1&stderr=1&tail=50"
|
||||||
|
|
||||||
@@ -41,215 +30,145 @@ curl -s -X DELETE -H "X-API-Key: $KEY" \
|
|||||||
"$BASE/api/endpoints/$EP/docker/containers/<ID>"
|
"$BASE/api/endpoints/$EP/docker/containers/<ID>"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Временный Alpine-контейнер (запустить команду на хосте)
|
### Временный Alpine-контейнер (выполнить команду на хосте)
|
||||||
|
|
||||||
Для разовых задач (записать файл, проверить путь и т.д.) — alpine с bind `/:/host`:
|
Для разовых задач — alpine с bind `/:/host`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:9000
|
BASE=http://localhost:9000
|
||||||
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
||||||
EP=1
|
EP=1
|
||||||
|
|
||||||
# 1. Создать
|
|
||||||
ID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
|
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-$$" \
|
"$BASE/api/endpoints/$EP/docker/containers/create?name=alpine-tmp-$$" \
|
||||||
-d '{
|
-d '{
|
||||||
"Image": "alpine",
|
"Image": "alpine",
|
||||||
"Cmd": ["sh", "-c", "echo hello from host > /host/tmp/test.txt && echo DONE"],
|
"Cmd": ["sh", "-c", "YOUR_COMMAND_HERE && echo DONE"],
|
||||||
"HostConfig": {
|
"HostConfig": {"Binds": ["/:/host"], "AutoRemove": false}
|
||||||
"Binds": ["/:/host"],
|
|
||||||
"AutoRemove": false
|
|
||||||
}
|
|
||||||
}' | jq -r '.Id')
|
}' | jq -r '.Id')
|
||||||
|
|
||||||
# 2. Запустить
|
|
||||||
curl -s -X POST -H "X-API-Key: $KEY" \
|
curl -s -X POST -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$ID/start"
|
"$BASE/api/endpoints/$EP/docker/containers/$ID/start"
|
||||||
|
|
||||||
# 3. Подождать завершения (1-2 сек) и забрать логи
|
|
||||||
sleep 2
|
sleep 2
|
||||||
curl -s -H "X-API-Key: $KEY" \
|
curl -s -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$ID/logs?stdout=1&stderr=1"
|
"$BASE/api/endpoints/$EP/docker/containers/$ID/logs?stdout=1&stderr=1"
|
||||||
|
|
||||||
# 4. Удалить
|
|
||||||
curl -s -X DELETE -H "X-API-Key: $KEY" \
|
curl -s -X DELETE -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$ID"
|
"$BASE/api/endpoints/$EP/docker/containers/$ID"
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ `AutoRemove: false` — обязательно, иначе контейнер удалится до того как получишь логи
|
> ⚠️ `AutoRemove: false` — обязательно, иначе контейнер удалится до получения логов
|
||||||
> ⚠️ Используй `alpine`, не `alpine/git` и подобные — у них есть ENTRYPOINT, `sh -c` не сработает
|
> ⚠️ Использовать `alpine`, не `alpine/git` — у git-образа свой ENTRYPOINT
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cloudflared — деплой
|
## Cloudflared — деплой (выполняет Кракен)
|
||||||
|
|
||||||
### Шаг 1 — Получить CF Tunnel token (делает Alex вручную)
|
CF Tunnel уже создан Alex'ом (`kraken` в Zero Trust), hostname настроен: `kraken.qentra.top → SSH → localhost:22`.
|
||||||
|
|
||||||
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:**
|
**CF Tunnel Token:**
|
||||||
```
|
```
|
||||||
<ВСТАВИТЬ СЮДА ТОКЕН ПОСЛЕ СОЗДАНИЯ ТОННЕЛЯ>
|
eyJhIjoiZjE0YTM3NWQ3NmU1ZTU4M2IzNjZhMDJhYjUyNDZiNDciLCJ0IjoiMmRkZDJiMjgtNjYwYy00NjQ0LTk1Y2ItY2Y1ZTQzNTBhMTA1IiwicyI6Ik5HVTRZalZtTURVdFptSm1OeTAwWVdGakxUaGlaamd0WmpFMFlUazVOekt3WTJWaCJ9
|
||||||
```
|
```
|
||||||
|
|
||||||
### Шаг 2 — Создать docker-compose.yml через alpine
|
### Шаг 1 — Убедиться что EP = 1
|
||||||
|
|
||||||
Используем alpine-контейнер с bind `/:/host` для записи файла:
|
```bash
|
||||||
|
curl -s -H "X-API-Key: ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g=" \
|
||||||
|
http://localhost:9000/api/endpoints | jq '[.[].Id]'
|
||||||
|
```
|
||||||
|
|
||||||
|
Если не `1` — запомнить реальный ID и использовать его вместо `1` в шагах ниже.
|
||||||
|
|
||||||
|
### Шаг 2 — Создать и запустить cloudflared контейнер
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:9000
|
BASE=http://localhost:9000
|
||||||
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
||||||
EP=1
|
EP=1
|
||||||
TOKEN="<CF_TUNNEL_TOKEN>"
|
TOKEN="eyJhIjoiZjE0YTM3NWQ3NmU1ZTU4M2IzNjZhMDJhYjUyNDZiNDciLCJ0IjoiMmRkZDJiMjgtNjYwYy00NjQ0LTk1Y2ItY2Y1ZTQzNTBhMTA1IiwicyI6Ik5HVTRZalZtTURVdFptSm1OeTAwWVdGakxUaGlaamd0WmpFMFlUazVOekt3WTJWaCJ9"
|
||||||
|
|
||||||
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="<CF_TUNNEL_TOKEN>"
|
|
||||||
|
|
||||||
# Создать контейнер
|
|
||||||
CID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
|
CID=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/create?name=cloudflared" \
|
"$BASE/api/endpoints/$EP/docker/containers/create?name=cloudflared" \
|
||||||
-d "{
|
-d "{
|
||||||
\"Image\": \"cloudflare/cloudflared:latest\",
|
\"Image\": \"cloudflare/cloudflared:latest\",
|
||||||
\"Cmd\": [\"tunnel\", \"--no-autoupdate\", \"run\"],
|
\"Cmd\": [\"tunnel\", \"--no-autoupdate\", \"run\"],
|
||||||
\"Env\": [\"TUNNEL_TOKEN=${TOKEN}\"],
|
\"Env\": [\"TUNNEL_TOKEN=$TOKEN\"],
|
||||||
\"HostConfig\": {
|
\"HostConfig\": {
|
||||||
\"RestartPolicy\": {\"Name\": \"unless-stopped\"},
|
\"RestartPolicy\": {\"Name\": \"unless-stopped\"},
|
||||||
\"NetworkMode\": \"host\"
|
\"NetworkMode\": \"host\"
|
||||||
}
|
}
|
||||||
}" | jq -r '.Id')
|
}" | jq -r '.Id')
|
||||||
|
|
||||||
# Запустить
|
echo "Container ID: $CID"
|
||||||
|
|
||||||
curl -s -X POST -H "X-API-Key: $KEY" \
|
curl -s -X POST -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$CID/start"
|
"$BASE/api/endpoints/$EP/docker/containers/$CID/start"
|
||||||
|
|
||||||
echo "Container ID: $CID"
|
echo "Started."
|
||||||
```
|
```
|
||||||
|
|
||||||
### Шаг 4 — Проверить логи
|
### Шаг 3 — Проверить логи
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:9000
|
BASE=http://localhost:9000
|
||||||
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
KEY="ptr_AJY+Ba9A7f6pcAHZfDD5koU4stkKgJCdbTEXLDLxn0g="
|
||||||
EP=1
|
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')
|
|
||||||
|
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" \
|
curl -s -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$CID/logs?stdout=1&stderr=1&tail=30"
|
"$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=0 ... protocol=http2
|
||||||
INF Connection ... registered connIndex=0
|
INF Registered tunnel connection connIndex=1 ...
|
||||||
INF Connection ... registered connIndex=1
|
INF Registered tunnel connection connIndex=2 ...
|
||||||
...
|
INF Registered tunnel connection connIndex=3 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Если видишь все 4 соединения — туннель активен.
|
Все 4 соединения = туннель активен. Если видишь `ERR` — проверить токен.
|
||||||
|
|
||||||
### Шаг 5 — Обновить статус в этой заметке
|
### Шаг 4 — Сохранить compose-файл (опционально, для удобства в будущем)
|
||||||
|
|
||||||
Заменить `⏳ 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
|
```bash
|
||||||
ssh ssh.kraken.qentra.top
|
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"
|
||||||
```
|
```
|
||||||
|
|
||||||
> `cloudflared` на Eagle уже есть (используется для `zulip.qentra.top`)
|
### Шаг 5 — Создать скилл по внешнему доступу
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Шаг 6 — Создать скилл по внешнему доступу (выполняет Кракен)
|
|
||||||
|
|
||||||
После того как cloudflared запущен и SSH-поддомен работает — создать скилл чтобы знать как пользоваться внешним доступом в будущем.
|
|
||||||
|
|
||||||
Скиллы живут в `/opt/data/skills/` (HDD-volume, переживают rebuild образа). Создать через terminal:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p /opt/data/skills/devops/kraken-external-access
|
mkdir -p /opt/data/skills/devops/kraken-external-access
|
||||||
cat > /opt/data/skills/devops/kraken-external-access/SKILL.md << 'EOF'
|
cat > /opt/data/skills/devops/kraken-external-access/SKILL.md << 'SKILLEOF'
|
||||||
---
|
---
|
||||||
name: kraken-external-access
|
name: kraken-external-access
|
||||||
category: devops
|
category: devops
|
||||||
description: Внешний доступ к Kraken через Cloudflare Tunnel — SSH с Eagle, Portainer API, управление cloudflared контейнером.
|
description: Внешний доступ к Kraken через Cloudflare Tunnel — SSH с Eagle, Portainer API, управление cloudflared.
|
||||||
triggers:
|
triggers:
|
||||||
- "доступ к кракену снаружи"
|
- "доступ к кракену снаружи"
|
||||||
- "ssh к кракену с орла"
|
- "ssh к кракену с орла"
|
||||||
@@ -259,19 +178,13 @@ triggers:
|
|||||||
|
|
||||||
# Kraken — External Access via Cloudflare Tunnel
|
# Kraken — External Access via Cloudflare Tunnel
|
||||||
|
|
||||||
## SSH с Eagle
|
## SSH с Eagle (уже настроено в ~/.ssh/config на Eagle)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ~/.ssh/config на Eagle (уже настроен):
|
ssh kraken.qentra.top
|
||||||
# Host ssh.kraken.qentra.top
|
|
||||||
# ProxyCommand cloudflared access ssh --hostname %h
|
|
||||||
# User kraken
|
|
||||||
# IdentityFile ~/.ssh/id_rsa
|
|
||||||
|
|
||||||
ssh ssh.kraken.qentra.top
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Portainer API (локально на Кракене)
|
## Portainer API
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:9000
|
BASE=http://localhost:9000
|
||||||
@@ -286,15 +199,11 @@ curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json?all
|
|||||||
## Управление cloudflared
|
## Управление cloudflared
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Статус
|
# Статус + логи
|
||||||
curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json" \
|
|
||||||
| jq '.[] | select(.Names[] | contains("cloudflared")) | {status: .Status}'
|
|
||||||
|
|
||||||
# Логи (последние 30 строк)
|
|
||||||
CID=$(curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json" \
|
CID=$(curl -s -H "X-API-Key: $KEY" "$BASE/api/endpoints/$EP/docker/containers/json" \
|
||||||
| jq -r '.[] | select(.Names[] | contains("cloudflared")) | .Id')
|
| jq -r '.[] | select(.Names[] | contains("cloudflared")) | .Id')
|
||||||
curl -s -H "X-API-Key: $KEY" \
|
curl -s -H "X-API-Key: $KEY" \
|
||||||
"$BASE/api/endpoints/$EP/docker/containers/$CID/logs?stdout=1&stderr=1&tail=30"
|
"$BASE/api/endpoints/$EP/docker/containers/$CID/logs?stdout=1&stderr=1&tail=30" | strings
|
||||||
|
|
||||||
# Рестарт
|
# Рестарт
|
||||||
curl -s -X POST -H "X-API-Key: $KEY" \
|
curl -s -X POST -H "X-API-Key: $KEY" \
|
||||||
@@ -303,22 +212,43 @@ curl -s -X POST -H "X-API-Key: $KEY" \
|
|||||||
|
|
||||||
## Питфолы
|
## Питфолы
|
||||||
|
|
||||||
- cloudflared запускается с `network_mode: host` — видит все локальные порты Кракена
|
- `network_mode: host` — cloudflared видит все локальные порты Кракена напрямую
|
||||||
- Если туннель отвалился — проверить логи: ищи `ERR` и `failed to`
|
|
||||||
- `restart: unless-stopped` — при падении поднимается автоматически
|
- `restart: unless-stopped` — при падении поднимается автоматически
|
||||||
- Токен туннеля хранится в env `TUNNEL_TOKEN` контейнера — не менять без пересоздания контейнера
|
- Токен в env `TUNNEL_TOKEN` — не менять без пересоздания контейнера
|
||||||
- CF Zero Trust tunnel: проверить статус на https://one.dash.cloudflare.com/ → Networks → Tunnels → kraken
|
- Статус туннеля: https://one.dash.cloudflare.com/ → Networks → Tunnels → kraken
|
||||||
|
- Если туннель не поднимается — искать `ERR` в логах cloudflared
|
||||||
|
|
||||||
## Связанные заметки в vault
|
## Связанные заметки
|
||||||
|
|
||||||
- `family/how-to/kraken-portainer-access.md` — полная инструкция по деплою
|
- `family/how-to/kraken-portainer-access.md` — полная инструкция по деплою
|
||||||
- `family/how-to/openmediavault-rpi5.md` — структура Docker на Кракене
|
- `family/how-to/openmediavault-rpi5.md` — структура Docker на Кракене
|
||||||
EOF
|
SKILLEOF
|
||||||
echo "Скилл создан: /opt/data/skills/devops/kraken-external-access/SKILL.md"
|
echo "Скилл создан."
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ `/opt/data/` — это HDD-backed volume, скилл переживёт `docker stop/start` и даже rebuild образа
|
> ⚠️ `/opt/data/` — HDD-volume, скилл переживёт rebuild образа
|
||||||
> ⚠️ Путь внутри контейнера — `/opt/data/skills/`, на хосте это `/srv/dev-disk-by-uuid-49e8f586.../docker/hermes/config/skills/`
|
|
||||||
|
### Шаг 6 — Обновить статус в этой заметке
|
||||||
|
|
||||||
|
Заменить первую строку `> Статус: ⏳ cloudflared pending deploy` на `> Статус: ✅ cloudflared запущен`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SSH-доступ с Eagle (после деплоя)
|
||||||
|
|
||||||
|
Добавить в `~/.ssh/config` на Eagle:
|
||||||
|
|
||||||
|
```
|
||||||
|
Host kraken.qentra.top
|
||||||
|
ProxyCommand cloudflared access ssh --hostname %h
|
||||||
|
User kraken
|
||||||
|
IdentityFile ~/.ssh/id_rsa
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем: `ssh kraken.qentra.top`
|
||||||
|
|
||||||
|
> `cloudflared` на Eagle уже установлен (используется для `zulip.qentra.top`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user