We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

  Назад к списку статей

Автоматизация сборки и публикации собственных репозиториев APT для Termux с использованием GitHub Actions

Если вы поддерживаете набор утилит, библиотек или внутренних инструментов для Termux, то удобнее централизованно распространять их через APT. Собственный репозиторий дает воспроизводимость сборок, предсказуемые версии и единый канал обновлений.

В этой статье разберем, как автоматизировать:

  • сборку пакетов под архитектуры Termux;
  • генерацию метаданных APT (Packages/Release);
  • подпись репозитория;
  • публикацию в виде статического хранилища (например, GitHub Pages) или на отдельный сервер;
  • обновление конфигурации на стороне клиента Termux.

Материал ориентирован на «собственные репозитории» и не затрагивает обход ограничений или какие-либо противозаконные сценарии.

Принципиальная схема пайплайна GitHub Actions

Типовой поток выглядит так:

  1. В репозитории Git хранится исходный код пакета и файлы метаданных (например, debian/control, debian/changelog или структура сборки под Termux).
  2. GitHub Actions запускает сборку для нужных целей (например, aarch64, arm и т.д.).
  3. Собранные .deb пакеты помещаются в структуру репозитория (включая pool/ и/или директории под архитектуры).
  4. Выполняется индексация APT через dpkg-scanpackages и формирование Release.
  5. Подписывается репозиторий (GPG) и итоговые файлы публикуются в целевой хостинг.

На выходе пользователь Termux получает URL к вашему репозиторию и может выполнять pkg upgrade / apt update / apt install для нужных пакетов.

Подготовка структуры проекта

Начните с репозитория, который GitHub Actions будет собирать. Практично хранить:

  • Исходники (ваш код).
  • Файлы сборки (scaffold под Debian/Termux Packaging).
  • Скрипты для индексации и публикации.
  • Конфиг репозитория (пути, компоненты, архитектуры).

Пример структуры:

repo/
  packages/
    mytool/
      debian/
        control
        rules
        changelog
      sources.list
      build.sh
  scripts/
    build_one.sh
    repo_index.sh
    repo_release.sh
    publish.sh
  .github/
    workflows/
      release.yml

В зависимости от того, как именно вы собираете под Termux (через Docker/скрипты, используете готовые тулчейны и т.д.), содержимое build.sh и rules будет различаться. Смысл — четко отделить «сборку пакета» от «формирования APT-индексов» и «публикации».

GitHub Secrets: что нужно для публикации и подписи

Для автоматизации безопасно хранить секреты в GitHub Secrets. Обычно нужны:

  • GPG_PRIVATE_KEY — приватный ключ для подписи (ASCII-armored или base64 — как решите);
  • GPG_PASSPHRASE — пароль (если ключ защищен);
  • REPO_PUBLISH_TOKEN — токен для загрузки артефактов (например, если вы публикуете на сервер по HTTPS/SSH или в репозиторий страниц);
  • адрес назначения: PUBLIC_REPO_URL или путь в артефакт-хранилище.

Примечание: не коммитьте приватный ключ в Git.

Сборка пакетов: базовый подход

Сборка под Termux часто требует специфичной среды (ABI, тулчейн, зависимости). На практике есть два распространенных варианта:

  • Сборка внутри контейнера (Docker) с корректным окружением.
  • Сборка через установленный тулчейн на runner’е (реже удобнее, чем контейнер).

Ниже пример «скелета» для сборки одного пакета с параметром архитектуры. Адаптируйте под вашу систему сборки:

#!/usr/bin/env bash
set -euo pipefail

PACKAGE_NAME="$1"
ARCH="$2"

echo "Building ${PACKAGE_NAME} for ${ARCH}"

# Пример: запускаем сборку (адаптируйте команды под ваш пакет)
# Можно использовать docker, qemu, или ваш тулчейн.
# Здесь оставим заглушку:
./packages/${PACKAGE_NAME}/build.sh "${ARCH}"

# Ожидаем, что build.sh положит результат в out/
# Например: out/${ARCH}/mytool_1.2.3_${ARCH}.deb

Главное — чтобы по завершении пайплайна у вас были .deb файлы, разложенные по предсказуемому пути.

Формирование APT-индексов (Packages и Release)

APT репозиторий обычно содержит:

  • dists/<codename>/main/binary-<arch>/Packages.gz
  • dists/<codename>/main/binary-<arch>/Release или общий dists/<codename>/Release в зависимости от вашей схемы;
  • файлы с checksums (MD5Sum, SHA256 и т.п.);
  • подписанные метаданные: InRelease или Release.gpg.

Скрипт индексации обычно включает:

  1. генерацию списка пакетов через dpkg-scanpackages;
  2. сжатие gzip;
  3. формирование Release и вычисление хэшей.

Пример скрипта индексации (адаптируйте под ваши пути):

#!/usr/bin/env bash
set -euo pipefail

REPO_ROOT="${1:-repo-out}"
DIST_CODENAME="${2:-stable}"
COMPONENT="${3:-main}"

ARCH_LIST=("$@") # Не используйте так в проде; ниже покажем концепт

echo "Indexing repo at ${REPO_ROOT} (dist=${DIST_CODENAME}, component=${COMPONENT})"

# Пример пути, куда вы положили .deb:
# repo-out/
#   pool/
#   dists/
#     stable/
#       main/
#         binary-aarch64/ (Packages...)
#         binary-arm/ (...)

# Допустим, вы храните .deb в pool/:
# pool/mytool_1.2.3_aarch64.deb и т.п.

Практический вариант, более близкий к типичному workflow:

#!/usr/bin/env bash
set -euo pipefail

REPO_OUT="${1:?REPO_OUT is required}"
DIST_CODENAME="${2:-stable}"
COMPONENT="${3:-main}"

# Архитектуры, которые вы собираете
ARCHES=("aarch64" "arm" "i686")

mkdir -p "${REPO_OUT}/dists/${DIST_CODENAME}/${COMPONENT}"

for ARCH in "${ARCHES[@]}"; do
  mkdir -p "${REPO_OUT}/dists/${DIST_CODENAME}/${COMPONENT}/binary-${ARCH}"

  # dpkg-scanpackages читает .deb в каталоге pool/
  # В реальности уточните, где лежат ваши deb-артефакты по архитектурам
  dpkg-scanpackages "${REPO_OUT}/pool" 
    | gzip -9c 
    > "${REPO_OUT}/dists/${DIST_CODENAME}/${COMPONENT}/binary-${ARCH}/Packages.gz"
done

Далее формируем Release. В простейшем подходе можно использовать apt-ftparchive, если он доступен в вашем окружении. Пример-скелет:

#!/usr/bin/env bash
set -euo pipefail

REPO_OUT="${1:?REPO_OUT is required}"
DIST_CODENAME="${2:-stable}"
COMPONENT="${3:-main}"

# Используйте apt-ftparchive, если доступно
# apt-ftparchive generate /path/to/config > dists/stable/Release
# Ниже — концептуальный пример.

Если apt-ftparchive недоступен, можно собирать Release вручную через шаблоны и утилиты расчета хэшей. Важно: Release должен содержать корректные поля (значения размеров/хэшей), иначе клиенты будут отклонять репозиторий.

Подпись репозитория (GPG) в GitHub Actions

Для корректной работы APT подписывайте Release. Типовая логика:

  1. Импортировать приватный ключ в gpg на runner’е;
  2. Сформировать Release (или InRelease);
  3. Выполнить подпись.

Пример шага GitHub Actions для импорта ключа:

- name: Import GPG key
  run: |
    echo "${GPG_PRIVATE_KEY}" > private.key
    gpg --batch --import private.key

И пример подписи:

- name: Sign Release
  env:
    GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
  run: |
    # Предполагаем, что Release уже создан:
    # ${REPO_OUT}/dists/stable/Release
    gpg --batch --yes --pinentry-mode loopback 
      --passphrase "${GPG_PASSPHRASE}" 
      -abs -o "${REPO_OUT}/dists/stable/Release.gpg" 
      "${REPO_OUT}/dists/stable/Release"

Если вы используете InRelease (clear-signed), то команда и формат будут отличаться. Главное — следить за тем, чтобы клиент Termux ожидал тот тип подписи, который вы публикуете.

Публикация: куда выкладывать repo

Варианты:

  • GitHub Pages (удобно для статических файлов): собираете структуру и пушите в ветку/папку для страниц.
  • Отдельный web-сервер (Nginx/Apache/S3 compatible): грузите файлы через токен.
  • Артефакт в GitHub (для тестов) — но APT обычно требует стабильного URL.

Смысл публикации: чтобы итоговые файлы лежали по URL вида:

https://example.com/your-repo/dists/stable/Release
https://example.com/your-repo/dists/stable/main/binary-aarch64/Packages.gz

Пример workflow GitHub Actions

Ниже пример .github/workflows/release.yml как каркас. Он показывает логику: сборка → индексация → Release → подпись → публикация.

name: Build and Publish Termux APT repo

on:
  workflow_dispatch:
  push:
    tags:
      - "v"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y dpkg-dev gzip gnupg

      - name: Build packages
        env:
          DIST_CODENAME: stable
        run: |
          set -euo pipefail

          # Создаем рабочую директорию под репозиторий
          REPO_OUT="repo-out"
          rm -rf "${REPO_OUT}"
          mkdir -p "${REPO_OUT}/pool"

          # Пример: собираем один пакет под набор архитектур
          # Адаптируйте под ваши пакеты/архитектуры
          PACKAGES=("mytool")
          ARCHES=("aarch64" "arm")

          for PKG in "${PACKAGES[@]}"; do
            for ARCH in "${ARCHES[@]}"; do
              echo "Building ${PKG} for ${ARCH}"
              # Выполняйте вашу сборку: должен появиться .deb
              ./scripts/build_one.sh "${PKG}" "${ARCH}"

              # Пример размещения .deb в pool/
              # Ожидаем, что build.sh кладет deb в out/${ARCH}/
              # и далее мы копируем:
              cp -v "out/${ARCH}/".deb "${REPO_OUT}/pool/"
            done
          done

      - name: Index repo
        run: |
          set -euo pipefail
          ./scripts/repo_index.sh "repo-out" "stable" "main"

      - name: Create Release file
        run: |
          set -euo pipefail
          # Реализуйте repo_release.sh под вашу структуру:
          # должен сформироваться repo-out/dists/stable/Release
          ./scripts/repo_release.sh "repo-out" "stable" "main"

      - name: Import GPG key
        run: |
          set -euo pipefail
          echo "${GPG_PRIVATE_KEY}" > private.key
          gpg --batch --import private.key

        env:
          GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

      - name: Sign Release
        run: |
          set -euo pipefail
          gpg --batch --yes --pinentry-mode loopback 
            --passphrase "${GPG_PASSPHRASE}" 
            -abs -o "repo-out/dists/stable/Release.gpg" 
            "repo-out/dists/stable/Release"
        env:
          GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

      - name: Publish
        run: |
          set -euo pipefail
          # Реализуйте publish.sh: например, пуш в gh-pages
          ./scripts/publish.sh "repo-out"
        env:
          REPO_PUBLISH_TOKEN: ${{ secrets.REPO_PUBLISH_TOKEN }}
          PUBLIC_REPO_URL: ${{ secrets.PUBLIC_REPO_URL }}

Даже если вы используете другой способ публикации, структура workflow не меняется: ключевые точки — артефакты, индексация, Release/подпись, публикация.

Подключение репозитория на стороне Termux

На устройстве в Termux добавьте ваш источник. Обычно редактируют файл репозиториев (в зависимости от версии Termux/apt):

  • обновление списка источников;
  • проверка, что APT видит Packages;
  • установка нужных пакетов.

Пример команд (адаптируйте под вашу конкретную версию и путь репозитория):

termux-change-repo

Если вы вручную добавляете строку источника, она обычно имеет вид:

deb https://example.com/your-repo stable main

Дальше:

pkg update
pkg upgrade
pkg install mytool

Если вы используете подпись Release, убедитесь, что клиентская система может проверить ключ. На стороне Termux обычно импортируют ключ (в зависимости от настроек APT). Практика: приложить открытый ключ в репозитории (например, repo.gpg) и документировать его для пользователей.

Тестирование и контроль качества

Чтобы избежать неприятных сюрпризов после публикации:

  • Включайте «проверку артефактов» перед публикацией: наличие .deb, корректность путей, наличие Packages.gz и Release.
  • Проверяйте, что Release.gpg формируется успешно и соответствует вашему ключу.
  • Добавляйте отдельный stage для smoke-test: скачайте Packages.gz и убедитесь, что в индексе присутствуют ожидаемые пакеты.

Пример проверки целостности (концепт):

ls -la repo-out/dists/stable/main/binary-aarch64/Packages.gz
ls -la repo-out/dists/stable/Release
ls -la repo-out/dists/stable/Release.gpg

Распространенные ошибки

  • Неправильные пути в dists/: APT жестко ожидает структуру. Согласуйте binary-ARCH, component и codename.
  • Отсутствие Packages.gz для архитектуры: клиент не сможет найти пакеты.
  • Release не соответствует Packages: несостыковка хэшей/размеров приводит к ошибкам проверки.
  • Сломанная подпись: неверный ключ или неподдерживаемый формат подписи.

Безопасность и эксплуатация

Для безопасной эксплуатации:

  • Минимизируйте доступ к секретам: выдавайте токены только на нужные операции.
  • Ограничьте публикацию: делайте публикацию только по тегам/релизам или вручную.
  • Логируйте шаги, но не выводите секреты.

Если вам необходимо использовать VPN, то только для создания локальной сети для разработки/доступа к внутренним ресурсам (например, приватный репозиторий или build-host). Не используйте VPN для обхода блокировок.

Заключение

Автоматизация сборки и публикации собственных APT-репозиториев для Termux с GitHub Actions — это практичный способ поддерживать набор пакетов в актуальном состоянии, ускорить релизы и сделать обновления предсказуемыми для пользователей. Ключевые элементы решения: воспроизводимая сборка .deb, генерация Packages.gz, корректный Release, подпись GPG и стабильная публикация по URL.

Если вы хотите спроектировать пайплайн под ваши пакеты, настроить структуру dists/, подпись и публикацию, а также провести аудит сборочных скриптов — обращайтесь в РыбинскЛАБ. Мы поможем довести процесс до надежного промышленного уровня.

* Текст статьи подготовлен и структурирован с использованием технологий искусственного интеллекта. Проверен и доработан перед публикацией.

Нужна помощь с настройкой Termux, Linux и серверов?

Я оказываю ИТ-услуги: настройка серверов, автоматизация, безопасность, помощь с Linux и инфраструктурой. Материалы сайта — только в ознакомительных и образовательных целях.

Связаться со мной
Поддержать проект