199 lines
9.3 KiB
Markdown
199 lines
9.3 KiB
Markdown
# Запуск проекта на платформе
|
||
|
||
Кладёшь в репу `.env` с доменом, пушишь — платформа собирает проект и поднимает
|
||
сайт с SSL. Форкать этот репо не нужно: он тут как справка и как источник двух
|
||
файлов, которые копируешь к себе.
|
||
|
||
## Быстрый старт
|
||
|
||
1. Скопируй в свой репозиторий два файла из [`starter/`](starter):
|
||
- `.forgejo/workflows/deploy.yml` — как есть, не редактируй
|
||
- `.env` — из `starter/.env.example`
|
||
2. В `.env` укажи домен: `DOMAIN=mysite.com`
|
||
3. Пропиши A-запись домена на `51.161.128.94`
|
||
4. Запушь в основную ветку. Через минуту-полторы сайт открыт по 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, раздаётся как статика, без
|
||
контейнера — самый быстрый вариант.
|
||
|
||
```env
|
||
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`.
|
||
|
||
```env
|
||
DOMAIN=mysite.com
|
||
DEPLOY=docker
|
||
APP_PORT=3000
|
||
```
|
||
|
||
### docker-db
|
||
|
||
То же, что docker, плюс SQLite: том монтируется в `/data`, в контейнер прокидывается
|
||
`DATABASE_URL=file:/data/app.db`. Том переживает редеплои. Миграции гоняешь сам в
|
||
entrypoint. `DATABASE_URL` в `RUNTIME_KEYS` добавлять не надо — она ставится сама.
|
||
|
||
```env
|
||
DOMAIN=mysite.com
|
||
DEPLOY=docker-db
|
||
APP_PORT=3000
|
||
```
|
||
|
||
## Домен и SSL
|
||
|
||
- `DOMAIN` обязателен. Заранее пропиши A-запись домена на `51.161.128.94`.
|
||
- `www` подключается сам, если у него тоже есть A-запись на наш IP. Не нужен —
|
||
поставь `WWW=false`.
|
||
- Сертификат выпускается автоматически, обычно за полминуты после первого деплоя.
|
||
На каждый домен — отдельный.
|
||
- Пока workflow не позеленел, не открывай сайт в обычном браузере: сертификата ещё
|
||
может не быть, и браузер закеширует ошибку. Дождись зелёного run или открой в
|
||
инкогнито.
|
||
|
||
Один сайт на нескольких доменах:
|
||
|
||
```env
|
||
EXTRA_DOMAINS=mysite.io,app.mysite.com
|
||
```
|
||
|
||
На каждый домен — свой сертификат, для каждого пропиши A-запись. `www` для
|
||
доп-доменов сам не добавляется (нужен — впиши `www.mysite.io` отдельным пунктом).
|
||
|
||
## Twitter
|
||
|
||
Чтобы в админке рядом с сайтом показывался твиттер проекта:
|
||
|
||
```env
|
||
TWITTER_URL=https://x.com/mysite
|
||
```
|
||
|
||
Принимается URL, `@handle` или просто `handle`. На сам сайт не влияет — только метка
|
||
в панели.
|
||
|
||
## Монорепозиторий
|
||
|
||
Один репозиторий = один сайт. Отдельного поля под папку приложения нет — сборка идёт
|
||
от корня репы. Поэтому:
|
||
|
||
- `.env` и `package.json` (или `Dockerfile`) держи в корне.
|
||
- static: корневой скрипт `build` должен собирать нужное приложение, а `BUILD_DIR` —
|
||
указывать на его вывод:
|
||
```env
|
||
BUILD_DIR=apps/web/dist
|
||
```
|
||
```json
|
||
{ "scripts": { "build": "npm run build -w apps/web" } }
|
||
```
|
||
- docker: `Dockerfile` в корне, контекст сборки — весь репозиторий, так что `COPY`
|
||
нужного пакета работает.
|
||
- Нужно несколько приложений на разные домены — заведи под каждое отдельный репозиторий.
|
||
|
||
## Установочный сабдомен (`curl get.домен | sh`)
|
||
|
||
Только для static, настраивается без админа:
|
||
|
||
1. Положи скрипт в `public/install.sh` (папка `public/` у Vite попадает в корень сборки).
|
||
2. Пропиши A-запись `get` → наш IP.
|
||
3. Добавь `INSTALL_SH=install.sh` в `.env` и запушь.
|
||
|
||
Платформа поднимет `get.домен`, выпустит SSL и будет отдавать этот файл как
|
||
`text/plain`. Убрал `INSTALL_SH` — сабдомен снимется на следующем деплое.
|
||
|
||
## Секреты
|
||
|
||
`.env` в контейнер не попадает — он читается только при деплое. Секреты заводишь в
|
||
Forgejo: репа → Settings → Actions → Secrets, имя секрета = имя переменной. Потом
|
||
перечисляешь нужные:
|
||
|
||
```env
|
||
RUNTIME_KEYS=DATABASE_URL,JWT_SECRET
|
||
```
|
||
|
||
В контейнер попадут только они. В коде читаешь как обычно — `process.env.DATABASE_URL`.
|
||
|
||
## Скорость сборки
|
||
|
||
Фронт собирается через bun — install в разы быстрее npm, закоммить `bun.lock`.
|
||
|
||
docker-образы собираются с BuildKit и кешем от предыдущего образа. Ставь зависимости
|
||
до копирования кода, чтобы слой install кешировался:
|
||
|
||
```dockerfile
|
||
COPY package.json package-lock.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
RUN npm run build
|
||
```
|
||
|
||
Для Next.js `output: 'standalone'` в `next.config` роняет образ с гигабайтов до
|
||
~200 МБ — деплой заметно быстрее.
|
||
|
||
## Выключить сайт
|
||
|
||
```env
|
||
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 git
|
||
```
|
||
Ремоут: `git 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`.
|
||
- Не разобрался — пиши админу.
|