Переезд с ghcr.io на встроенный Container Registry Gitea
Build & Push Image / Build and push to Gitea Registry (push) Failing after 14s
Build & Push Image / Build and push Caddy (Cloudflare DNS) image (push) Failing after 13s
CI / fmt + clippy + test (push) Has been cancelled

CI (build/deploy) и рантайм самого бэкенда (провижининг новых нод через
NodeService::provision_node_via_ssh — раньше читал GHCR_TOKEN, теперь
GITEA_REGISTRY_TOKEN) теперь используют gitea.netrunner-vpn.com вместо
ghcr.io. .github/workflows остались нетронутыми — та копия для настоящего
GitHub CI, там ghcr.io уместен и дальше (свой GITHUB_TOKEN, не наш секрет).
This commit is contained in:
2026-07-10 20:44:03 +07:00
parent 51788f73ee
commit c617c05233
7 changed files with 54 additions and 39 deletions
+4 -1
View File
@@ -120,7 +120,10 @@ COOKIE_SECURE=true
# =====================================================================
# === DEPLOYMENT & REPOSITORY SETTINGS ===
# =====================================================================
GHCR_TOKEN=ghp_ТВОЙ_ТОКЕН_ОТ_ГИТХАБА_ДЛЯ_ДОСТУПА_К_РЕЕСТРУ
# Токен Gitea (право write:package) — нужен самому бэкенду в рантайме для
# провижининга новых нод (см. NodeService::provision_node_via_ssh, шлёт этот
# же токен на ноду, чтобы она тоже могла тянуть образ с Gitea Registry).
GITEA_REGISTRY_TOKEN=CHANGE_ME_GITEA_REGISTRY_TOKEN
VPS_IP=CHANGE_ME_VPS_IP
DEPLOY_DIR=/root/netrunner-core
BINARY_NAME=netrunner-control-plane
+17 -15
View File
@@ -1,9 +1,13 @@
# Копия .github/workflows/build.yml для Gitea Actions. Отличие от оригинала:
# логин на ghcr.io использует secrets.GHCR_TOKEN (настоящий GitHub PAT с
# правами write:packages), а не secrets.GITHUB_TOKEN — автотокен Gitea валиден
# только для самого Gitea (API/пакеты этого инстанса), на ghcr.io им не
# залогиниться. Секрет GHCR_TOKEN нужно завести отдельно в настройках этого
# репозитория/организации в Gitea.
# реестр — встроенный Container Registry самой Gitea (gitea.netrunner-vpn.com),
# не ghcr.io — секрет secrets.GITHUB_TOKEN там валиден только на самом
# GitHub. Логин — токеном Gitea с правом write:package
# (secrets.GITEA_REGISTRY_TOKEN), один и тот же токен используется во всех
# репозиториях, где собираются образы (netrunner-backend/netrunner-landing/
# netrunner-proxy) — пакеты в Gitea принадлежат аккаунту, не конкретному
# репозиторию, заводить по секрету на каждый репозиторий не нужно, но
# значение нужно продублировать в Settings каждого из них (Gitea не даёт
# организационных секретов на уровне всего аккаунта для personal-репозиториев).
name: Build & Push Image
on:
@@ -13,12 +17,12 @@ on:
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/netrunner-control-plane
REGISTRY: gitea.netrunner-vpn.com
IMAGE_NAME: nineap/netrunner-control-plane
jobs:
build:
name: Build and push to GHCR
name: Build and push to Gitea Registry
runs-on: ubuntu-24.04
permissions:
contents: read
@@ -30,12 +34,12 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
- name: Log in to Gitea Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
password: ${{ secrets.GITEA_REGISTRY_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
@@ -76,12 +80,12 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
- name: Log in to Gitea Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
password: ${{ secrets.GITEA_REGISTRY_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
@@ -90,9 +94,7 @@ jobs:
file: ./Dockerfile.caddy
push: true
# Захардкожено, не ${{ github.repository_owner }}: он резолвится в
# "nineAp" (смешанный регистр), Docker такие теги отклоняет — та же
# причина, по которой deploy.yml тоже хардкодит "nineap" для
# основного образа вместо репозиторного контекста.
# "nineAp" (смешанный регистр), Docker такие теги отклоняет.
tags: ${{ env.REGISTRY }}/nineap/netrunner-caddy-cloudflare:latest
cache-from: type=gha,scope=caddy
cache-to: type=gha,mode=max,scope=caddy
+22 -12
View File
@@ -1,5 +1,6 @@
# Копия .github/workflows/deploy.yml для Gitea Actions. secrets.GHCR_TOKEN
# здесь уже был настоящим PAT (не автотокеном), менять не пришлось.
# Копия .github/workflows/deploy.yml для Gitea Actions. Образы тянутся из
# встроенного Container Registry самой Gitea (gitea.netrunner-vpn.com), не
# ghcr.io — secrets.GITEA_REGISTRY_TOKEN, не GHCR_TOKEN/GITHUB_TOKEN.
# Триггер workflow_run (авто-деплой после успешной сборки) поддерживается не
# во всех версиях Gitea Actions — если deploy-dev не срабатывает автоматически
# после build, проверить версию Gitea или временно дергать деплой вручную
@@ -22,7 +23,7 @@ on:
workflow_dispatch:
inputs:
image_tag:
description: "Тег образа в GHCR для прод-деплоя"
description: "Тег образа в Gitea Registry для прод-деплоя"
required: true
default: "latest"
@@ -37,8 +38,8 @@ jobs:
ref: ${{ github.event.workflow_run.head_sha }}
# Копируем compose-файл + Caddyfile (примонтированный конфиг, не образ —
# сам Caddy-образ, как и образ бэкенда, дев-сервер тянет из GHCR, собран
# в build.yml::build-caddy. Собирать xcaddy прямо на VPS один раз уже не
# сам Caddy-образ, как и образ бэкенда, дев-сервер тянет из Gitea Registry,
# собран в build.yml::build-caddy. Собирать xcaddy прямо на VPS один раз уже не
# уложилось в таймаут SSH-деплоя и уронило весь прогон).
- name: Sync compose file to Dev VPS
uses: appleboy/scp-action@v0.1.7
@@ -56,7 +57,7 @@ jobs:
host: ${{ vars.DEV_VPS_IP }}
username: root
key: ${{ secrets.DEV_SSH_PRIVATE_KEY }}
envs: "DB_PASSWORD,CF_API_TOKEN,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME"
envs: "DB_PASSWORD,CF_API_TOKEN,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME,GITEA_REGISTRY_TOKEN"
script: |
set -e
cd /root/netrunner-core
@@ -72,6 +73,10 @@ jobs:
ARGON_SALT=${ARGON_SALT}
TON_MASTER_WALLET=${TON_MASTER_WALLET}
PROXY_INTERNAL_SECRET=${PROXY_INTERNAL_SECRET}
# Нужен самому бэкенду в рантайме, не только CI — см.
# NodeService::provision_node_via_ssh (шлёт этот же токен на новую
# ноду, чтобы она тоже могла тянуть образ с gitea.netrunner-vpn.com).
GITEA_REGISTRY_TOKEN=${GITEA_REGISTRY_TOKEN}
CRYPTOBOT_API_TOKEN=${CRYPTOBOT_API_TOKEN}
CRYPTOBOT_TESTNET=true
BOT_ENABLED=true
@@ -87,11 +92,11 @@ jobs:
EOF
chmod 600 .env
export IMAGE="ghcr.io/nineap/netrunner-control-plane:latest"
export CADDY_IMAGE="ghcr.io/nineap/netrunner-caddy-cloudflare:latest"
export IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest"
export CADDY_IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-caddy-cloudflare:latest"
echo "🚀 Deploying ${IMAGE} to DEV"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
echo "${{ secrets.GITEA_REGISTRY_TOKEN }}" | docker login gitea.netrunner-vpn.com -u ${{ github.actor }} --password-stdin
docker compose -f docker-compose.dev-remote.yml pull
docker compose -f docker-compose.dev-remote.yml up -d --remove-orphans
@@ -109,6 +114,7 @@ jobs:
CRYPTOBOT_API_TOKEN: ${{ secrets.DEV_CRYPTOBOT_API_TOKEN }}
TELOXIDE_TOKEN: ${{ secrets.DEV_TELOXIDE_TOKEN }}
BOT_USERNAME: ${{ vars.DEV_BOT_USERNAME }}
GITEA_REGISTRY_TOKEN: ${{ secrets.GITEA_REGISTRY_TOKEN }}
deploy-prod:
name: Pull & restart on Prod VPS
@@ -133,7 +139,7 @@ jobs:
host: ${{ vars.VPS_IP }}
username: root
key: ${{ secrets.SSH_PRIVATE_KEY }}
envs: "DB_PASSWORD,DATA_VPS_IP,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,GRAFANA_PUBLIC_URL,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME,WEB_APP_BASE_URL"
envs: "DB_PASSWORD,DATA_VPS_IP,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,GRAFANA_PUBLIC_URL,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME,WEB_APP_BASE_URL,GITEA_REGISTRY_TOKEN"
script: |
set -e
cd /root/netrunner-core
@@ -156,6 +162,9 @@ jobs:
BOT_USERNAME=${BOT_USERNAME}
WEB_APP_BASE_URL=${WEB_APP_BASE_URL}
PROXY_INTERNAL_SECRET=${PROXY_INTERNAL_SECRET}
# Нужен самому бэкенду в рантайме, не только CI — см.
# NodeService::provision_node_via_ssh.
GITEA_REGISTRY_TOKEN=${GITEA_REGISTRY_TOKEN}
PORT=8080
SUBSCRIPTION_CHECK_INTERVAL=1800
NODE_HEALTH_CHECK_INTERVAL=60
@@ -168,10 +177,10 @@ jobs:
EOF
chmod 600 .env
export IMAGE="ghcr.io/nineap/netrunner-control-plane:${{ github.event.inputs.image_tag }}"
export IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-control-plane:${{ github.event.inputs.image_tag }}"
echo "🚀 Deploying ${IMAGE}"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
echo "${{ secrets.GITEA_REGISTRY_TOKEN }}" | docker login gitea.netrunner-vpn.com -u ${{ github.actor }} --password-stdin
# Тянем свежий образ, прогоняем миграции (one-shot) и поднимаем сервисы.
docker compose -f docker-compose.prod.yml pull
@@ -193,3 +202,4 @@ jobs:
TELOXIDE_TOKEN: ${{ secrets.TELOXIDE_TOKEN }}
BOT_USERNAME: ${{ vars.BOT_USERNAME }}
WEB_APP_BASE_URL: ${{ vars.WEB_APP_BASE_URL }}
GITEA_REGISTRY_TOKEN: ${{ secrets.GITEA_REGISTRY_TOKEN }}
+3 -3
View File
@@ -6,7 +6,7 @@
services:
# One-shot: применяет миграции и завершается. Требует только DATABASE_URL.
migrate:
image: ${IMAGE:-ghcr.io/nineap/netrunner-control-plane:latest}
image: ${IMAGE:-gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest}
container_name: netrunner-migrate-dev
command: ["./netrunner-control-plane", "--migrate"]
environment:
@@ -19,7 +19,7 @@ services:
- netrunner_grid_dev
app:
image: ${IMAGE:-ghcr.io/nineap/netrunner-control-plane:latest}
image: ${IMAGE:-gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest}
container_name: netrunner-app-dev-remote
restart: always
ports:
@@ -85,7 +85,7 @@ services:
# компиляция xcaddy (Go, тянет много модулей) на этой машине один раз уже
# не уложилась в таймаут SSH-деплоя и уронила весь прогон.
caddy:
image: ${CADDY_IMAGE:-ghcr.io/nineap/netrunner-caddy-cloudflare:latest}
image: ${CADDY_IMAGE:-gitea.netrunner-vpn.com/nineap/netrunner-caddy-cloudflare:latest}
container_name: netrunner-caddy-dev
restart: always
ports:
+2 -2
View File
@@ -14,7 +14,7 @@
services:
# One-shot: применяет миграции и завершается. Требует только DATABASE_URL.
migrate:
image: ${IMAGE:-ghcr.io/nineap/netrunner-control-plane:latest}
image: ${IMAGE:-gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest}
container_name: netrunner-migrate
command: ["./netrunner-control-plane", "--migrate"]
environment:
@@ -24,7 +24,7 @@ services:
- netrunner_grid
app:
image: ${IMAGE:-ghcr.io/nineap/netrunner-control-plane:latest}
image: ${IMAGE:-gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest}
container_name: netrunner-app
restart: always
ports:
+2 -2
View File
@@ -153,8 +153,8 @@ impl NodeService {
let sess = Self::connect_ssh(ip, "root", password)?;
// 3. Подготавливаем команды автоматизации
let gh_token = std::env::var("GHCR_TOKEN").map_err(|_| {
AppError::Internal("GHCR_TOKEN не задан — провижининг ноды невозможен".into())
let gh_token = std::env::var("GITEA_REGISTRY_TOKEN").map_err(|_| {
AppError::Internal("GITEA_REGISTRY_TOKEN не задан — провижининг ноды невозможен".into())
})?;
// Секрет и публичный URL этого же бэкенда — нода должна ходить именно
// сюда для проверки токенов/лимитов (--require-auth), а не работать
+4 -4
View File
@@ -10,11 +10,11 @@ if ! command -v docker &> /dev/null; then
sh get-docker.sh
fi
echo "[*] Step 3: Logging into ghcr.io via Control Plane token..."
echo "$GH_TOKEN" | docker login ghcr.io -u nineap --password-stdin
echo "[*] Step 3: Logging into Gitea Registry via Control Plane token..."
echo "$GH_TOKEN" | docker login gitea.netrunner-vpn.com -u nineap --password-stdin
echo "[*] Step 4: Pulling the latest Netrunner image..."
docker pull ghcr.io/nineap/netrunner-proxy:latest
docker pull gitea.netrunner-vpn.com/nineap/netrunner-proxy:latest
echo "[*] Step 5: Starting Netrunner Proxy at port ${NODE_PORT}..."
# NODE_PORT/SNI_DOMAIN/BACKEND_URL/PROXY_INTERNAL_SECRET подставляет
@@ -34,7 +34,7 @@ docker run -d \
--cap-add DAC_OVERRIDE \
--device /dev/net/tun:/dev/net/tun \
-e PROXY_INTERNAL_SECRET="$PROXY_INTERNAL_SECRET" \
ghcr.io/nineap/netrunner-proxy:latest \
gitea.netrunner-vpn.com/nineap/netrunner-proxy:latest \
./netrunner-proxy \
--port "$NODE_PORT" \
--decoy-host "$SNI_DOMAIN" \