init platform/launch

This commit is contained in:
root 2026-07-17 11:59:36 +00:00
parent 4cb188a340
commit 87470cc453

284
README.md
View file

@ -1,3 +1,283 @@
# launch # Как запустить свой проект на платформе
Как запустить свой проект на платформе — гайд, стартер и платформенный action Один файл `.env` + один пуш → сайт на твоём домене с автоматическим SSL.
Это единственный репозиторий, который нужно знать: тут и гайд, и файлы стартера,
и сам платформенный action.
---
## TL;DR — 4 шага
1. Скопируй в **свой** репозиторий 2 файла из папки [`starter/`](starter) этого репо:
- `.forgejo/workflows/deploy.yml`**не трогать** (тянет платформенный action по ссылке)
- `.env` — из `starter/.env.example`
Форкать/клонировать этот репо **не надо** — деплой цепляется к твоей репе по
самому факту наличия `.forgejo/workflows/deploy.yml`.
2. Заполни `.env`, минимум:
```env
DOMAIN=mysite.com
```
3. Пропиши **A-запись** домена → IP платформы **`51.161.128.94`**.
4. `git push` в дефолтную ветку. Через ~3090 сек сайт открыт на `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` → статика раздаётся напрямую, **без
контейнера**. Деплой за секунды; редеплой = только заливка новых файлов.
```env
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`.
```env
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`. Том переживает редеплои.
```env
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), обычно за 3060 сек после первого деплоя,
когда DNS уже указывает на наш IP. Отдельный серт на каждый домен. Ничего
настраивать не надо.
- **Не открывай сайт в браузере, пока workflow не зелёный** — пока идёт деплой,
валидного серта ещё может не быть, и браузер закеширует «сломанный SSL». Дождись
зелёного run в **Actions** (или открой в инкогнито).
### Доп. домены — один сайт на нескольких доменах
```env
DOMAIN=mysite.com
EXTRA_DOMAINS=mysite.io,app.mysite.com,promo.xyz
```
Тот же сайт на всех доменах, на **каждый** — свой авто-SSL. От тебя: A-запись
каждого домена на наш IP. `www.` для доп-доменов сам не добавляется — если нужен,
впиши `www.mysite.io` явным пунктом.
---
## Twitter / X проекта
Хочешь, чтобы в **админ-панели** рядом с сайтом показывался его твиттер — добавь в
`.env`:
```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` — указывать на его вывод:
```env
DOMAIN=mysite.com
BUILD_DIR=apps/web/dist # куда собирается целевое приложение
```
```jsonc
// 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`-сайтов:
1. Положи скрипт в репу → `public/install.sh` (папка `public/` у Vite попадает в
`dist/` как есть → окажется в корне сайта).
2. **DNS:** A-запись `get` → IP платформы (host = `get`).
3. В `.env`: `INSTALL_SH=install.sh``git push`.
CI сам поднимет `get.<domain>`, выпустит SSL и будет отдавать `install.sh` как
`text/plain`. Убери `INSTALL_SH` и запушь — сабдомен снимется. В админке этот
сабдомен виден в строке «сабдомены».
---
## Секреты (DATABASE_URL, API-ключи)
`.env` в runtime контейнера **не попадает** (парсится только при деплое). Секреты:
1. **Forgejo → репа → Settings → Actions → Secrets → Add Secret.** Имя секрета = имя
переменной окружения (`DATABASE_URL`, `JWT_SECRET`).
2. В `.env` перечисли, какие прокинуть:
```env
RUNTIME_KEYS=DATABASE_URL,JWT_SECRET
```
3. В коде: `process.env.DATABASE_URL`.
Платформа берёт **только** ключи из `RUNTIME_KEYS`. (Только для `docker`/`docker-db`.)
---
## Скорость билда
Фронт собирается через **bun** (install в 1030× быстрее npm). Закоммить lock:
```bash
bun install # создаст bun.lock
git add bun.lock && git commit -m "chore: bun lock" && git push
```
### docker-сайты — кеш слоёв и лёгкие образы
Сборка идёт с **BuildKit** и `--cache-from` предыдущего образа. Чтобы это работало:
- ставь зависимости ДО копирования кода (слой install кешируется):
```dockerfile
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
```
- cache-mount'ы:
```dockerfile
# 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` роняет образ с ~13 ГБ до
~150250 МБ → деплой заметно быстрее.
---
## Выключить сайт (kill-switch)
```env
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 git
```
Ремоут: `git 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/`](starter). Платформенный action — [`action.yml`](action.yml)._