187 lines
8.5 KiB
Markdown
187 lines
8.5 KiB
Markdown
# Deploy (Forgejo Actions)
|
||
|
||
Push в `main` → сайт на твоём домене с SSL. Один файл `.env`, один пуш.
|
||
|
||
> Флоу на **Forgejo Actions**. Один `.env` + `.forgejo/workflows/deploy.yml` в
|
||
> репе — и push. Никакого GitLab.
|
||
|
||
---
|
||
|
||
## TL;DR
|
||
|
||
1. Скопируй в **свой** репозиторий 2 файла из этого стартера:
|
||
`.forgejo/workflows/deploy.yml` (не трогать) и `.env` (из `.env.example`).
|
||
**Форкать/клонировать весь стартер не надо** — он лишь источник этих файлов;
|
||
деплой цепляется к твоей репе по самому факту наличия `deploy.yml`.
|
||
2. Заполни `.env` (см. `.env.example`), минимум:
|
||
```env
|
||
DOMAIN=mysite.com
|
||
```
|
||
3. Пропиши A-запись домена на IP сервера платформы.
|
||
4. `git push` в `main`. Через ~30–90 сек сайт открыт на `https://mysite.com`.
|
||
|
||
Дальше любой push = редеплой. Файл `.forgejo/workflows/deploy.yml` трогать не нужно.
|
||
|
||
---
|
||
|
||
## Три типа проектов
|
||
|
||
Тип определяется по `.env` (`DEPLOY=...`) или авто-детектом.
|
||
|
||
### 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 не работают (только статика).
|
||
|
||
### 2. docker — фронт + бэкенд в контейнере
|
||
|
||
Положи `Dockerfile` в корень. Платформа собирает образ и поднимает контейнер,
|
||
проксирует домен на него. Контейнер должен слушать порт из `APP_PORT`.
|
||
|
||
```env
|
||
DOMAIN=mysite.com
|
||
DEPLOY=docker # или просто наличие Dockerfile
|
||
APP_PORT=3000 # порт, который слушает контейнер (default 80)
|
||
```
|
||
|
||
### 3. docker-db — + персистентная база (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` — она ставится автоматически.
|
||
|
||
---
|
||
|
||
## Доп. домены — один сайт на нескольких доменах
|
||
|
||
По умолчанию сайт отдаётся на `DOMAIN` (+ `www.` авто, если у www есть A-запись на
|
||
наш IP). Нужен тот же сайт ещё на других доменах — перечисли их через запятую:
|
||
|
||
```env
|
||
DOMAIN=mysite.com
|
||
EXTRA_DOMAINS=mysite.io,app.mysite.com,promo.xyz
|
||
```
|
||
|
||
Платформа раздаёт сайт на всех доменах и на **каждый** выпускает свой SSL-серт
|
||
автоматически. От тебя — прописать A-запись каждого домена на IP платформы и
|
||
`git push`. `www.` для доп-доменов сам не добавляется — если нужен, впиши
|
||
`www.mysite.io` явным пунктом. Нет A-записи → в логе `::warning::`, серт выпустится,
|
||
как только DNS укажет сюда.
|
||
|
||
> One-liner `curl get.<domain> | sh` — особый случай, см. `INSTALL_SH` в
|
||
> `.env.example` (отдаёт один файл-скрипт с сабдомена `get.`).
|
||
|
||
---
|
||
|
||
## Скорость билда
|
||
|
||
Платформа собирает фронт через **bun** (install в 10–30× быстрее npm). Закоммить
|
||
lock-файл:
|
||
|
||
```bash
|
||
bun install # создаст bun.lock
|
||
git add bun.lock && git commit -m "chore: bun lock" && git push
|
||
```
|
||
|
||
`package.json` и твои `npm run build` скрипты bun понимает as-is. Не коммить
|
||
`node_modules` / `dist` (они в `.gitignore`).
|
||
|
||
### docker-сайты — кеш слоёв и лёгкие образы
|
||
|
||
Платформа собирает с **BuildKit** и `--cache-from` предыдущего образа: если слои не
|
||
менялись, пересборка почти мгновенная. Чтобы это работало на полную:
|
||
|
||
- **Коммить lockfile** и ставь зависимости ДО копирования кода — слой install
|
||
кешируется, пока deps не менялись:
|
||
```dockerfile
|
||
COPY package.json package-lock.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
RUN npm run build
|
||
```
|
||
- **Cache-mount'ы** (BuildKit включён) — install/apt не качают заново между сборками,
|
||
а Next держит инкрементальный кеш компиляции:
|
||
```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` роняет образ
|
||
с ~1–3 ГБ до ~150–250 МБ → деплой заметно быстрее (меньше экспорт + запуск).
|
||
|
||
---
|
||
|
||
## Секреты (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`; у static-сайта runtime-секретов нет.)
|
||
|
||
---
|
||
|
||
## Выключить сайт (kill-switch)
|
||
|
||
В `.env`:
|
||
```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 на каждый) |
|
||
| `INSTALL_SH` | — | static: отдать файл-скрипт на `get.<domain>` (`curl \| sh`) |
|
||
| `ENABLED` | `true` | `false` — выключить сайт |
|
||
| `RUNTIME_KEYS`| — | docker: список секретов в контейнер |
|
||
|
||
---
|
||
|
||
## Не открывай сайт в браузере, пока workflow не зелёный
|
||
|
||
Пока деплой идёт, по домену ещё может не быть валидного серта. Браузер может
|
||
закешировать "сломанный SSL". Дождись зелёного run в **Actions**, потом открывай
|
||
(или открой в инкогнито).
|