13 KiB
Как запустить свой проект на платформе
Один файл .env + один пуш → сайт на твоём домене с автоматическим SSL.
Это единственный репозиторий, который нужно знать: тут и гайд, и файлы стартера,
и сам платформенный action.
TL;DR — 4 шага
-
Скопируй в свой репозиторий 2 файла из папки
starter/этого репо:.forgejo/workflows/deploy.yml— не трогать (тянет платформенный action по ссылке).env— изstarter/.env.example
Форкать/клонировать этот репо не надо — деплой цепляется к твоей репе по самому факту наличия
.forgejo/workflows/deploy.yml. -
Заполни
.env, минимум:DOMAIN=mysite.com -
Пропиши A-запись домена → IP платформы
51.161.128.94. -
git pushв дефолтную ветку. Через ~30–90 сек сайт открыт наhttps://mysite.com.
Дальше любой push = редеплой. deploy.yml трогать не нужно никогда.
Как это работает (флоу)
git push
│
▼
Forgejo Actions запускает .forgejo/workflows/deploy.yml
│ (uses: https://git.extract.team/platform/launch@main)
▼
platform/launch action:
├─ клонирует твою репу
├─ читает .env → DOMAIN, тип деплоя (static / docker / docker-db)
├─ билд: static → bun build | docker → docker build
├─ публикует статику в /srv/sites │ или поднимает контейнер
└─ пишет фрагмент Caddy на твой домен
▼
Caddy автоматически выпускает SSL (Let's Encrypt) → https://mysite.com живой
Один репозиторий = один сайт (один .env, один DOMAIN).
Тип проекта: static / docker / docker-db
Тип определяется полем DEPLOY в .env или авто-детектом (по наличию Dockerfile).
1. static — фронт (90% проектов)
Vite / CRA / Next static export. bun build → статика раздаётся напрямую, без
контейнера. Деплой за секунды; редеплой = только заливка новых файлов.
DOMAIN=mysite.com
# DEPLOY=static # дефолт, если в корне НЕТ Dockerfile
# BUILD_DIR=dist # Vite=dist (дефолт), CRA=build, Next export=out
- Vite + React — ничего настраивать, дефолт.
- CRA —
BUILD_DIR=build. - Next.js static export — в
next.config:output: 'export',images: { unoptimized: true },trailingSlash: true; в.env—BUILD_DIR=out. SSR / API routes / Server Actions в static-режиме не работают.
2. docker — фронт + бэкенд в контейнере
Положи Dockerfile в корень. Платформа собирает образ, поднимает контейнер и
проксирует домен на него. Контейнер должен слушать порт из APP_PORT.
DOMAIN=mysite.com
DEPLOY=docker # или просто наличие Dockerfile
APP_PORT=3000 # порт контейнера (default 80)
3. docker-db — docker + персистентная база (SQLite)
Как docker, плюс платформа монтирует named-volume в /data и прокидывает
DATABASE_URL=file:/data/app.db. Том переживает редеплои.
DOMAIN=mysite.com
DEPLOY=docker-db
APP_PORT=3000
В коде читаешь process.env.DATABASE_URL. Миграции (drizzle/prisma) запускай в
своём entrypoint — платформа их не делает. Не указывай DATABASE_URL в
RUNTIME_KEYS (ставится автоматически).
Домен и SSL
DOMAIN— обязательное поле. Заранее пропиши A-запись домена на IP платформы51.161.128.94(у своего регистратора).www.подключается автоматически, если уwww.<domain>тоже есть A-запись на наш IP. Не нужен — поставьWWW=false.- SSL выпускается сам (Let's Encrypt), обычно за 30–60 сек после первого деплоя, когда DNS уже указывает на наш IP. Отдельный серт на каждый домен. Ничего настраивать не надо.
- Не открывай сайт в браузере, пока workflow не зелёный — пока идёт деплой, валидного серта ещё может не быть, и браузер закеширует «сломанный SSL». Дождись зелёного run в Actions (или открой в инкогнито).
Доп. домены — один сайт на нескольких доменах
DOMAIN=mysite.com
EXTRA_DOMAINS=mysite.io,app.mysite.com,promo.xyz
Тот же сайт на всех доменах, на каждый — свой авто-SSL. От тебя: A-запись
каждого домена на наш IP. www. для доп-доменов сам не добавляется — если нужен,
впиши www.mysite.io явным пунктом.
Twitter / X проекта
Хочешь, чтобы в админ-панели рядом с сайтом показывался его твиттер — добавь в
.env:
TWITTER_URL=https://x.com/mysite
Принимается полный URL, @handle или голый handle (TWITTER= тоже работает).
Платформа нормализует и покажет как 𝕏 @mysite. Ни на деплой, ни на сайт не влияет —
только метаданные для админки.
Монорепозиторий
Платформа деплоит один сайт на репозиторий (один .env, один DOMAIN). Отдельного
поля «папка приложения» нет — сборка идёт от корня репы. Поэтому для монорепо:
.envиpackage.json(илиDockerfile) — в корне репозитория.- static: корневой скрипт
buildдолжен собирать нужное приложение (через workspaces / turbo / nx), аBUILD_DIR— указывать на его вывод:DOMAIN=mysite.com BUILD_DIR=apps/web/dist # куда собирается целевое приложение// package.json в корне { "scripts": { "build": "npm run build -w apps/web" } } - docker:
Dockerfileв корне, контекст сборки = весь репозиторий, так что он спокойноCOPY apps/web …и собирает нужный пакет. ЗадайAPP_PORT. - Нужно задеплоить несколько приложений из одного монорепо на разные домены — сделай под каждое отдельный репозиторий (один репо = один сайт).
Установочный сабдомен curl get.<domain> | sh (self-service)
Красивый one-liner установки — делается сам, без админа, для static-сайтов:
- Положи скрипт в репу →
public/install.sh(папкаpublic/у Vite попадает вdist/как есть → окажется в корне сайта). - DNS: A-запись
get→ IP платформы (host =get). - В
.env:INSTALL_SH=install.sh→git push.
CI сам поднимет get.<domain>, выпустит SSL и будет отдавать install.sh как
text/plain. Убери INSTALL_SH и запушь — сабдомен снимется. В админке этот
сабдомен виден в строке «сабдомены».
Секреты (DATABASE_URL, API-ключи)
.env в runtime контейнера не попадает (парсится только при деплое). Секреты:
- Forgejo → репа → Settings → Actions → Secrets → Add Secret. Имя секрета = имя
переменной окружения (
DATABASE_URL,JWT_SECRET). - В
.envперечисли, какие прокинуть:RUNTIME_KEYS=DATABASE_URL,JWT_SECRET - В коде:
process.env.DATABASE_URL.
Платформа берёт только ключи из RUNTIME_KEYS. (Только для docker/docker-db.)
Скорость билда
Фронт собирается через bun (install в 10–30× быстрее npm). Закоммить lock:
bun install # создаст bun.lock
git add bun.lock && git commit -m "chore: bun lock" && git push
docker-сайты — кеш слоёв и лёгкие образы
Сборка идёт с BuildKit и --cache-from предыдущего образа. Чтобы это работало:
- ставь зависимости ДО копирования кода (слой install кешируется):
COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build - cache-mount'ы:
# syntax=docker/dockerfile:1.7 RUN --mount=type=cache,target=/root/.npm npm ci RUN --mount=type=cache,target=/app/.next/cache npm run build - Next.js →
output: 'standalone'вnext.configроняет образ с ~1–3 ГБ до ~150–250 МБ → деплой заметно быстрее.
Выключить сайт (kill-switch)
ENABLED=false
Push → контейнер/файлы удаляются, домен отдаёт 404. Убери строку (или true) +
push → поднимается обратно. Том и секреты сохраняются. (Админ может выключить и без
коммита — переменной ENABLED=false в Settings → Actions → Variables.)
Все переменные .env
| Key | Default | Зачем |
|---|---|---|
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 проекта для админки (@handle / URL) |
INSTALL_SH |
— | static: отдать файл-скрипт на get.<domain> (curl | sh) |
RUNTIME_KEYS |
— | docker: список секретов в контейнер |
ENABLED |
true |
false — выключить сайт |
Доступ к гиту (один раз)
- Форж: https://git.extract.team, логин — твой username.
- SSH:
git@git.extract.team:2223. Добавь ключ: Settings → SSH/GPG Keys, затем в~/.ssh/config:
Ремоут:Host git.extract.team Port 2223 User gitgit remote set-url origin git@git.extract.team:<логин>/<репа>.git(или HTTPS — логин + пароль).
Частые проблемы
- 502 / сайт не грузится сразу после пуша — деплой ещё идёт или серт выпускается. Дождись зелёного run в Actions.
build output 'dist' not found— не таBUILD_DIR(CRA →build, Next export →out, монорепо → путь до вывода приложения).no .env/no package.json— оба файла должны быть в корне репозитория.- SSL не выпускается — нет A-записи домена на
51.161.128.94(в логе деплоя будет::warning::). Пропиши DNS — серт выпустится сам. - Застрял — пиши админу.
Файлы для копирования — в starter/. Платформенный action — action.yml.