Всем привет!

В данном туториале я расскажу вам как можно задеплоить gitea на своём железе с использованием docker-compose подключить drone, для возможности автоматизации тестирования и доставки собственных приложений, настроить reverse-proxy через nginx для доступа через сеть и включить portainer для мониторинга запущенных контейнеров.

Шаг 1 - проверяем наличие необходимых программ

Для запуска полного стека нам будет необходим следующий софт:

  • docker - стоит v20.10.21, хотя версии больше 18 должны подойти;

  • docker-compose - главное что бы поддерживался compose v3, у меня стоит 2.12.2;

  • go - golang v1.19.3+ будет использоваться для получения сертификатов через lego, тем кто не планирует размещение сайта данный пункт можно пропустить.

Инструкций по установке в зависимости от системы более чем достаточно, установка не должна быть сложной. Для проверки, что всё в норме можно запустить данный скрипт:

go version;docker version;docker compose version

Скрипт должен показать установленные версии программ.

Шаг 2 - запускаем локальный инстанс gitea

Минимальный compose для запуска локального инстанса выглядит следующим образом:

services:
  gitea:
    image: gitea/gitea:1.17.3
    container_name: gitea
    restart: unless-stopped
    environment:
      USER_UID: 1000
      USER_GID: 1000
      GITEA__server__APP_DATA_PATH: /data/gitea
      GITEA__server__DOMAIN: localhost
      GITEA__server__HTTP_PORT: 80
      GITEA__server__ROOT_URL: http://localhost/
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 80:80

Создаем рабочую директорию, в ней файл docker-compose.yml и добавляем туда следующее содержимое. После запускаем команду docker compose up.

После мы можем перейти в браузере по адресу localhost, порт можно не указывать, и мы должны увидеть окно настройки gitea:

Параметры менять не обязательно, можно оставить всё как есть и запустить локальную копию. После небольшого ожидания мы должны увидеть локальную версию gitea, уже готовую к использованию.

У gitea очень большой набор настроек, и список различных модификаций, далее постараюсь подсветить список самого интересного для первого запуска:

  • DEFAULT_USER_IS_RESTRICTED (service) - позволяет ограничить в правах новых пользователей (не могут просматривать контент и выполнять никакие действия), подойдет для закрытых команд;

  • MAX_CREATION_LIMIT (repository) - пользователи могут просматривать репозитории и создавать issue, но ограниченны определенным количеством в создании собственных;

  • PROTOCOL (server) - будет ли использоваться http или https, если планируется выносить сайт в сеть, то строго рекомендуется использовать https или настроить https после через nginx;

  • DOMAIN (server) - название домена сервера, которое в случае использование поддомена должно так же включать и его sub.example.pw;

  • ROOT_URL (server) - должен совпадать с используемой ссылкой и включать http:// или https://.

Полный список настроек есть на официальном сайте.

Так же есть много различных опций по настройке тем, плагинов и других плюшек.

Шаг 3 - подключаем drone-ci

Далее можно подключить к gitea дрона, что бы автоматизировать процесс тестирования и анализа кода:

Дрон подключается к gitea как сторонее приложение и требует предоставления ему соответствующих прав, через графу настройки -> приложения:

Там нужно указать название приложения и его адрес для перехода по ссылке в формате:

И после создать кнопку создать приложение, сохраненные secret/ client_id сохранить для compose. Далее необходимо сгенерировать токен в этой же вкладке, опять же для compose.

Теперь добавим дрон в сам с полученными параметрами docker-compose:

services:
  gitea:
    image: gitea/gitea:1.17.3
    container_name: gitea
    restart: unless-stopped
    environment:
      USER_UID: 1000
      USER_GID: 1000
      GITEA__server__APP_DATA_PATH: /data/gitea
      GITEA__server__DOMAIN: localhost
      GITEA__server__HTTP_PORT: 80
      GITEA__server__ROOT_URL: http://localhost/
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 80:80

  drone:
    image: drone/drone:2.15
    container_name: drone
    restart: unless-stopped
    environment:
      DRONE_DATABASE_DRIVER: sqlite3
      DRONE_DATABASE_DATASOURCE: /data/database.sqlite
      DRONE_GITEA_SERVER: http://localhost/
      DRONE_GIT_ALWAYS_AUTH: false
      DRONE_RPC_SECRET: very-secret
      DRONE_SERVER_PROTO: http
      DRONE_SERVER_HOST: localhost:81
      DRONE_TLS_AUTOCERT: false
      DRONE_USER_CREATE: username:dancheg97,machine:false,admin:true,token:55f24eb3d61ef6ac5e83d550178638dc
      DRONE_GITEA_CLIENT_ID: 1445cb69-6bf9-4803-beec-f914477b8053
      DRONE_GITEA_CLIENT_SECRET: gto_2rybvjtwcmcbd2k2k3exm5sguipdb6xjngv5n5jfjdszg6onwyva
    volumes:
      - ./drone:/data
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 81:80
    depends_on:
      - gitea

  drone-runner:
    image: drone/drone-runner-docker:1.8.2
    container_name: droner
    restart: unless-stopped
    environment:
      DRONE_RPC_PROTO: http
      DRONE_RPC_HOST: drone
      DRONE_RPC_SECRET: very-secret
      DRONE_RUNNER_NAME: drone-runner
      DRONE_RUNNER_CAPACITY: 2
      DRONE_RUNNER_NETWORKS: habrz_default
      DRONE_DEBUG: false
      DRONE_TRACE: false
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - drone

Полученный токен идет в env DRONE_USER_CREATE, после token. Запускаем compose и подключаем drone.

Если запутались в процессе настройки, то тут официальная дока.

Авторизуем приложение и можем настроить дрон. В данный момент drone может начать выдавать ошибку:

  • invalid character '<' looking for beginning of value

Не стоит из-за этого сильно переживать, тк после настройки nginx данная проблема быстро решается.

Шаг 4 - перенаправляем трафик на наш ip адрес, при необходимости настраиваем маршрутизатор.

Сейчас наша задача - перенаправить весь входящий трафик на нашу железку, что бы при переходе по ссылке можно было всегда попадать в одно место.

Как правило данное действие состоит из двух этапов, во-первых - перенаправляем DNS записи у предоставителя нашего домена (на fozzy это выглядит так, сильных отличий в других местах быть не должно, интерфейс будет однообразен):

Для каждого поддомена рекомендуется создать отдельную запись.

Далее необходимо перенаправить трафик в роутере в локальной сети (в случае с использованием виртуалки достаточно просто открыть порты).

На моём роутере это выглядит примерно так:

Шаг 5 - настраиваем nginx

Теперь когда у нас уже есть gitea и drone, можно приступить к настройке nginx:

  nginx:
    image: nginx:1.23-alpine
    container_name: nginx
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro
      - ./.lego/certificates:/certs:ro
      - ./web:/web:ro
    depends_on:
      - gitea
      - drone

Добавляем следующие строки в уже написанный docker-compose. Так мы добавим nginx к существующим сервисам, но сначала нам нужно прописать конфиг для nginx.

Я буду писать его в файле - nginx/nginx.conf (и потом маунтить его в докер).

Он будет включать 2 пункта - в зависимости от поддомена (которые вы можете задать как хотите) будет перенаправлять трафик на запущенные контейнеры:

server {
    listen 80;
    listen 443 ssl;
    server_name gitea.dancheg97.ru;
    ssl_certificate /certs/gitea.example.pw.crt;
    ssl_certificate_key /certs/gitea.example.pw.key;
    location / {
        proxy_pass http://gitea/;
    }
}

server {
    listen 80;
    listen 443 ssl;
    server_name drone.dancheg97.ru;
    ssl_certificate /certs/drone.example.pw.crt;
    ssl_certificate_key /certs/drone.example.pw.key;
    location / {
        proxy_pass http://drone/;
    }
}

Теперь мы установим cli-утилиту которая называется lego и получим бесплатные сертификаты запустив данный скрипт в нашей директории с docker-compose.yml файлом.

go install github.com/go-acme/lego/v4/cmd/lego@latest
sudo lego --email="mail@gmail.com" --domains="gitea.example.pw" --http run
sudo lego --email="mail@gmail.com" --domains="drone.example.pw" --http run
sudo chown -R dancheg97:dancheg97 .lego

при этом певая строка - установка сертбота, последняя - предоставление доступа к сертам всем пользователям на устройстве (замените имя на своего пользователя).

Далее мы можем запускать nginx вместе с остальными контейнерами.

Шаг 6 - Подключаем portainer

Теперь мы можем опционально подключить портейнер (не всем это нужно, даже без него у нас есть рабочая конфигурация).

Далее этого добавим в compose еще 1 сервис:

  portainer:
    image: portainer/portainer-ce:2.0.0
    container_name: portainer
    command: -H unix:///var/run/docker.sock
    restart: always
    environment:
      - VIRTUAL_HOST=portainer.example.pw
      - VIRTUAL_PORT=9000
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer:/data

И выполним похожие действия по настройке домена/серта/nginx-a.

Настроенный портейнер позволит мониторить состояние остальных сервисов:

Данный сетап позволяет полностью уйти от использования внешних систем контроля версий (в моём случае - github) и оставлять все свои данные на собственных носителях. Настройка требует времени, но появляются следующие плюшки:

  • Полностью open-source + self-hosted стек.

  • Полный контроль за всеми данными в системе, отсутствие облаков и третьих лиц.

  • Удобный drone-ci для автоматизации операций с контейнерами.

  • Возможность моментальной автоматической выкладки в сеть верифицированного контента.

При наличии свободной железки (старый ноут или raspberry), система будет обходится примерно в 200Р в месяц в зависимости от стоимости домена/статического ip адреса у провайдера.

Мой собственный инстанс после настройки тем и других докрутов выглядит примерно так:

https://fmnx.su/

Моя версия docker-compose.yml (многое докрутил под себя):

services:
  nginx:
    image: nginx:1.23-alpine
    container_name: nginx
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro
      - ./.lego/certificates:/certs:ro
      - ./web:/web:ro
    depends_on:
      - gitea
      - drone

  gitea:
    image: gitea/gitea:1.17.3
    container_name: gitea
    restart: unless-stopped
    environment:
      USER_UID: 1000
      USER_GID: 1000
      GITEA__server__APP_DATA_PATH: /data/gitea
      GITEA__server__DOMAIN: gitea.dancheg97.ru
      GITEA__server__SSH_DOMAIN: gitea.dancheg97.ru
      GITEA__server__HTTP_PORT: 80
      GITEA__server__ROOT_URL: https://gitea.dancheg97.ru/
      GITEA__server__DISABLE_SSH: false
      GITEA__server__SSH_PORT: 22
      GITEA__server__SSH_LISTEN_PORT: 22
      GITEA__server__LFS_START_SERVER: true
      GITEA__server__LFS_JWT_SECRET: xxx
      GITEA__server__OFFLINE_MODE: false
      GITEA__ui__THEMES: gitea,arc-green,plex,aquamarine,dark,dracula,hotline,organizr,space-gray,hotpink,onedark,overseerr,nord,earl-grey
      GITEA__ui__DEFAULT_THEME: earl-grey
      GITEA__service_DISABLE_REGISTRATION: false
      GITEA__service_REQUIRE_SIGNIN_VIEW: false
      GITEA__service_REGISTER_EMAIL_CONFIRM: false
      GITEA__service_ENABLE_NOTIFY_MAIL: false
      GITEA__service_ALLOW_ONLY_EXTERNAL_REGISTRATION: false
      GITEA__service_ENABLE_CAPTCHA: false
      GITEA__service_DEFAULT_KEEP_EMAIL_PRIVATE: false
      GITEA__service_DEFAULT_ALLOW_CREATE_ORGANIZATION: true
      GITEA__service_DEFAULT_ENABLE_TIMETRACKING: true
      GITEA__service_NO_REPLY_ADDRESS: noreply.localhost
      GITEA__service_DEFAULT_USER_IS_RESTRICTED: true
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro

  drone:
    image: drone/drone:2.15
    container_name: drone
    restart: unless-stopped
    environment:
      DRONE_DATABASE_DRIVER: sqlite3
      DRONE_DATABASE_DATASOURCE: /data/database.sqlite
      DRONE_GITEA_SERVER: https://gitea.dancheg97.ru/
      DRONE_GIT_ALWAYS_AUTH: false
      DRONE_RPC_SECRET: xxx
      DRONE_SERVER_PROTO: https
      DRONE_SERVER_HOST: drone.dancheg97.ru
      DRONE_TLS_AUTOCERT: false
      DRONE_USER_CREATE: xxx
      DRONE_GITEA_CLIENT_ID: xxx
      DRONE_GITEA_CLIENT_SECRET: xxx
    volumes:
      - ./drone:/data
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - gitea

  drone-runner:
    image: drone/drone-runner-docker:1.8.2
    container_name: droner
    restart: unless-stopped
    environment:
      DRONE_RPC_PROTO: http
      DRONE_RPC_HOST: drone
      DRONE_RPC_SECRET: xxx
      DRONE_RUNNER_NAME: drone-runner
      DRONE_RUNNER_CAPACITY: 2
      DRONE_RUNNER_NETWORKS: composer_default
      DRONE_DEBUG: false
      DRONE_TRACE: false
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - drone

При наличии вопросов в настройке прошу обращаться: tlg @dancheg97