From c835ac983a6983eab0a8c19d3993a4476dbd52ff Mon Sep 17 00:00:00 2001 From: nineap Date: Thu, 9 Jul 2026 15:27:18 +0700 Subject: [PATCH] =?UTF-8?q?Gitea=20Actions:=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=B0=20+=20?= =?UTF-8?q?=D0=B4=D0=B5=D0=BF=D0=BB=D0=BE=D0=B9=20=D0=BD=D0=B0=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D0=BF=D1=80=D0=BE=D0=BA=D1=81?= =?UTF-8?q?=D0=B8-=D0=BD=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .gitea/workflows/build.yml — cargo build --release + docker build/push в ghcr.io/nineap/netrunner-proxy:latest (Dockerfile сам не компилирует Rust, ждёт уже готовый target/release/netrunner-server). - .gitea/workflows/deploy.yml — только вручную (workflow_dispatch), параметр target: имя ноды из nodes.json или "all". Job "resolve" фильтрует список, job "deploy" — matrix по результату, каждая нода видна в прогоне отдельной строкой. Деплой пересоздаёт контейнер (pull+rm+run), не просто restart — иначе новый образ не подхватится. - nodes.json — список нод (name/host/proxy_port/decoy_host), шаблон с CHANGE_ME — заполнить реальными IP. Нужные секреты: GHCR_TOKEN (тот же, что и в остальных репо), PROXY_NODES_SSH_KEY (общий master-ключ на все ноды), PROXY_INTERNAL_SECRET, BACKEND_URL (те же значения, что уже настроены у бэкенда). --- .gitea/workflows/build.yml | 48 +++++++++++++++++ .gitea/workflows/deploy.yml | 103 ++++++++++++++++++++++++++++++++++++ nodes.json | 14 +++++ 3 files changed, 165 insertions(+) create mode 100644 .gitea/workflows/build.yml create mode 100644 .gitea/workflows/deploy.yml create mode 100644 nodes.json diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..b551c6c --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,48 @@ +# Собирает netrunner-server (release-бинарник) и пушит Docker-образ в ghcr.io. +# Dockerfile сам не компилирует Rust — он просто копирует уже готовый +# target/release/netrunner-server (см. Dockerfile), поэтому cargo build идёт +# отдельным шагом перед docker build, не внутри него. +# +# Нужен секрет GHCR_TOKEN — настоящий GitHub PAT с правом write:packages +# (автотокен Gitea для ghcr.io не годится, см. остальные .gitea/workflows/ +# в других репозиториях — та же причина). +name: Build & Push Proxy Image + +on: + push: + branches: [main] + tags: ["v*"] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + + - name: Build release binary + run: cargo build --release -p netrunner-server + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GHCR_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ghcr.io/nineap/netrunner-proxy:latest diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..f997d8d --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,103 @@ +# Деплой на прокси-ноды из nodes.json. Список серверов — сам файл в корне +# репозитория (name/host/proxy_port/decoy_host на каждую ноду), поддерживать +# его руками при добавлении/выводе серверов. +# +# Запуск только вручную (workflow_dispatch) — параметр target: имя ноды из +# nodes.json (поле "name") или "all" для обновления сразу всех. Job "resolve" +# фильтрует список по этому параметру и отдаёт job'у "deploy" как matrix — +# каждая нода тогда видна в прогоне отдельной строкой, с отдельным логом. +# GH/Gitea Actions не поддерживают выпадающий список (type: choice) с +# вариантами из файла — только статичные в самом yaml, а список нод меняется +# независимо от workflow, поэтому просто текстовое поле, значение — точное +# имя из nodes.json. +# +# Каждый деплой пересоздаёт контейнер (pull нового образа + rm + run) — не +# просто restart, иначе новый образ не подхватится, раз контейнер уже создан +# со старым слоем. +# +# Секреты (общие на все ноды — один master-ключ, как и при первичном +# провижининге через netrunner-backend, см. NodeService::provision_node_via_ssh): +# - PROXY_NODES_SSH_KEY — приватный SSH-ключ (root на все ноды) +# - PROXY_INTERNAL_SECRET — тот же секрет, что и PROXY_INTERNAL_SECRET у бэкенда +# - BACKEND_URL — публичный адрес control plane (WEB_APP_BASE_URL у бэкенда) +# - GHCR_TOKEN — тот же, что и в build.yml +name: Deploy Proxy Nodes + +on: + workflow_dispatch: + inputs: + target: + description: 'Имя ноды из nodes.json ("name"), или "all" — обновить сразу все' + required: true + default: "all" + +jobs: + resolve: + runs-on: ubuntu-24.04 + outputs: + targets: ${{ steps.filter.outputs.targets }} + steps: + - uses: actions/checkout@v4 + + - name: Filter nodes.json by input + id: filter + run: | + set -e + command -v jq >/dev/null || (apt-get update && apt-get install -y jq) + + target="${{ github.event.inputs.target }}" + if [ "$target" = "all" ]; then + filtered=$(jq -c '.' nodes.json) + else + filtered=$(jq -c --arg n "$target" '[.[] | select(.name == $n)]' nodes.json) + fi + + count=$(echo "$filtered" | jq 'length') + if [ "$count" -eq 0 ]; then + echo "Нода '$target' не найдена в nodes.json" >&2 + exit 1 + fi + + echo "targets=$filtered" >> "$GITHUB_OUTPUT" + + deploy: + needs: resolve + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.resolve.outputs.targets) }} + runs-on: ubuntu-24.04 + steps: + - name: Deploy to ${{ matrix.name }} (${{ matrix.host }}) + uses: appleboy/ssh-action@v1 + with: + host: ${{ matrix.host }} + username: root + key: ${{ secrets.PROXY_NODES_SSH_KEY }} + script: | + set -e + echo "🚀 Деплой на ${{ matrix.name }} (${{ matrix.host }}:${{ matrix.proxy_port }})" + + echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + docker pull ghcr.io/nineap/netrunner-proxy:latest + + docker stop netrunner-proxy 2>/dev/null || true + docker rm netrunner-proxy 2>/dev/null || true + + docker run -d \ + --name netrunner-proxy \ + --restart always \ + --network host \ + --cap-add NET_ADMIN --cap-add NET_RAW --cap-add DAC_OVERRIDE \ + --device /dev/net/tun:/dev/net/tun \ + -e PROXY_INTERNAL_SECRET="${{ secrets.PROXY_INTERNAL_SECRET }}" \ + ghcr.io/nineap/netrunner-proxy:latest \ + ./netrunner-proxy \ + --port "${{ matrix.proxy_port }}" \ + --decoy-host "${{ matrix.decoy_host }}" \ + --require-auth \ + --backend-url "${{ secrets.BACKEND_URL }}" \ + --health-port 9091 + + docker image prune -f + echo "✅ ${{ matrix.name }} обновлена." diff --git a/nodes.json b/nodes.json new file mode 100644 index 0000000..04263df --- /dev/null +++ b/nodes.json @@ -0,0 +1,14 @@ +[ + { + "name": "nl-1", + "host": "CHANGE_ME_IP_1", + "proxy_port": 443, + "decoy_host": "www.debian.org" + }, + { + "name": "sg-1", + "host": "CHANGE_ME_IP_2", + "proxy_port": 8443, + "decoy_host": "ubuntu.com" + } +]