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" + } +]