| infra | ||
| starter | ||
| action.yml | ||
| README.md | ||
Запуск проекта на платформе
Кладёшь в репу .env с доменом, пушишь — платформа собирает проект и поднимает
сайт с SSL. Форкать этот репо не нужно: он тут как справка и как источник двух
файлов, которые копируешь к себе.
Быстрый старт
- Скопируй в свой репозиторий два файла из
starter/:.forgejo/workflows/deploy.yml— как есть, не редактируй.env— изstarter/.env.example
- В
.envукажи домен:DOMAIN=mysite.com - Пропиши A-запись домена на
51.161.128.94 - Запушь в основную ветку. Через минуту-полторы сайт открыт по HTTPS.
Дальше каждый push пересобирает и передеплоивает. deploy.yml больше не трогаешь.
Что происходит при пуше
Workflow дёргает платформенный action (action.yml из этого репо): он клонирует
твою репу, читает .env, определяет тип сборки, собирает и публикует, прописывает
домен в Caddy. Caddy сам выпускает сертификат Let's Encrypt.
Типы проектов
Тип берётся из DEPLOY в .env, либо определяется сам: есть Dockerfile — docker,
нет — static.
static
Фронт на Vite / CRA / Next export. Собирается через bun, раздаётся как статика, без контейнера — самый быстрый вариант.
DOMAIN=mysite.com
# BUILD_DIR=dist # Vite=dist, CRA=build, Next export=out
Для Next.js в static-режиме нужно в next.config: output: 'export',
images.unoptimized: true, trailingSlash: true, и BUILD_DIR=out. SSR и API
routes в этом режиме не работают.
docker
Свой Dockerfile в корне. Платформа собирает образ, поднимает контейнер и
проксирует на него домен. Контейнер должен слушать APP_PORT.
DOMAIN=mysite.com
DEPLOY=docker
APP_PORT=3000
docker-db
То же, что docker, плюс SQLite: том монтируется в /data, в контейнер прокидывается
DATABASE_URL=file:/data/app.db. Том переживает редеплои. Миграции гоняешь сам в
entrypoint. DATABASE_URL в RUNTIME_KEYS добавлять не надо — она ставится сама.
DOMAIN=mysite.com
DEPLOY=docker-db
APP_PORT=3000
Домен и SSL
DOMAINобязателен. Заранее пропиши A-запись домена на51.161.128.94.wwwподключается сам, если у него тоже есть A-запись на наш IP. Не нужен — поставьWWW=false.- Сертификат выпускается автоматически, обычно за полминуты после первого деплоя. На каждый домен — отдельный.
- Пока workflow не позеленел, не открывай сайт в обычном браузере: сертификата ещё может не быть, и браузер закеширует ошибку. Дождись зелёного run или открой в инкогнито.
Один сайт на нескольких доменах:
EXTRA_DOMAINS=mysite.io,app.mysite.com
На каждый домен — свой сертификат, для каждого пропиши A-запись. www для
доп-доменов сам не добавляется (нужен — впиши www.mysite.io отдельным пунктом).
Чтобы в админке рядом с сайтом показывался твиттер проекта:
TWITTER_URL=https://x.com/mysite
Принимается URL, @handle или просто handle. На сам сайт не влияет — только метка
в панели.
Монорепозиторий
Один репозиторий = один сайт. Отдельного поля под папку приложения нет — сборка идёт от корня репы. Поэтому:
.envиpackage.json(илиDockerfile) держи в корне.- static: корневой скрипт
buildдолжен собирать нужное приложение, аBUILD_DIR— указывать на его вывод:BUILD_DIR=apps/web/dist{ "scripts": { "build": "npm run build -w apps/web" } } - docker:
Dockerfileв корне, контекст сборки — весь репозиторий, так чтоCOPYнужного пакета работает. - Нужно несколько приложений на разные домены — заведи под каждое отдельный репозиторий.
Установочный сабдомен (curl get.домен | sh)
Только для static, настраивается без админа:
- Положи скрипт в
public/install.sh(папкаpublic/у Vite попадает в корень сборки). - Пропиши A-запись
get→ наш IP. - Добавь
INSTALL_SH=install.shв.envи запушь.
Платформа поднимет get.домен, выпустит SSL и будет отдавать этот файл как
text/plain. Убрал INSTALL_SH — сабдомен снимется на следующем деплое.
Секреты
.env в контейнер не попадает — он читается только при деплое. Секреты заводишь в
Forgejo: репа → Settings → Actions → Secrets, имя секрета = имя переменной. Потом
перечисляешь нужные:
RUNTIME_KEYS=DATABASE_URL,JWT_SECRET
В контейнер попадут только они. В коде читаешь как обычно — process.env.DATABASE_URL.
Скорость сборки
Фронт собирается через bun — install в разы быстрее npm, закоммить bun.lock.
docker-образы собираются с BuildKit и кешем от предыдущего образа. Ставь зависимости до копирования кода, чтобы слой install кешировался:
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
Для Next.js output: 'standalone' в next.config роняет образ с гигабайтов до
~200 МБ — деплой заметно быстрее.
Выключить сайт
ENABLED=false
Push — контейнер и файлы удаляются, домен отдаёт 404. Убрал строку (или true) —
вернулся. Том и секреты остаются. Админ может выключить и без коммита — переменной
ENABLED=false в Settings → Actions → Variables.
Переменные .env
| Ключ | Дефолт | Зачем |
|---|---|---|
DOMAIN |
— | Обязателен (кроме ENABLED=false) |
DEPLOY |
auto | static / docker / docker-db |
BUILD_DIR |
dist |
static: папка сборки (в монорепо — путь до вывода приложения) |
APP_PORT |
80 |
docker: порт контейнера |
WWW |
auto |
false — не подключать www |
EXTRA_DOMAINS |
— | доп. домены через запятую, свой SSL на каждый |
TWITTER_URL |
— | твиттер/X для админки |
INSTALL_SH |
— | static: отдать скрипт на get.<domain> |
RUNTIME_KEYS |
— | docker: какие секреты прокинуть в контейнер |
ENABLED |
true |
false — выключить сайт |
Доступ к гиту
- Форж: https://git.extract.team, логин прежний.
- SSH:
git@git.extract.team:2223, ключ добавляешь в Settings → SSH/GPG Keys.
Ремоут:Host git.extract.team Port 2223 User gitgit remote set-url origin git@git.extract.team:<логин>/<репа>.git
Если не работает
- 502 сразу после пуша — деплой ещё идёт или выпускается сертификат, дождись зелёного run.
build output 'dist' not found— не таBUILD_DIR(CRA →build, Next export →out, монорепо → путь до вывода приложения).no .env/no package.json— оба файла должны лежать в корне репы.- Сертификат не выпускается — нет A-записи домена на
51.161.128.94. - Не разобрался — пиши админу.