# Деплой на прокси-ноды из 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 у бэкенда # - GHCR_TOKEN — тот же, что и в build.yml # # Repo Variable (vars.*, не secret — публичный URL, не даёт доступа сам по себе): # - BACKEND_URL — публичный адрес control plane (WEB_APP_BASE_URL у бэкенда) 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 "${{ vars.BACKEND_URL }}" \ --health-port 9091 docker image prune -f echo "✅ ${{ matrix.name }} обновлена."