launch/README.md

192 lines
9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Запуск проекта на платформе
Кладёшь в репу `.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. Собирается через bun, раздаётся как статика, без контейнера —
самый быстрый вариант.
```env
DOMAIN=mysite.com
# BUILD_DIR=dist # Vite=dist, CRA=build
```
### 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, и для docker. Настраивается без админа:
1. Положи скрипт в репу — в корень или в `public/` (например `install.sh`).
2. Пропиши A-запись `get` → наш IP.
3. Добавь `INSTALL_SH=install.sh` в `.env` и запушь.
Платформа поднимет `get.домен`, выпустит SSL и будет отдавать этот файл как
`text/plain`. Убрал `INSTALL_SH` — сабдомен снимется на следующем деплое.
## Переменные окружения
Всё, что положишь в `.env`, автоматически прокидывается в контейнер (`docker` /
`docker-db`) как переменные окружения. Просто пиши в `.env` и пушь — ничего отдельно
настраивать не надо.
```env
DOMAIN=mysite.com
DATABASE_URL=postgres://user:pass@host/db
JWT_SECRET=...
API_KEY=...
```
В коде читаешь как обычно — `process.env.DATABASE_URL`. Служебные ключи платформы
(`DOMAIN`, `DEPLOY`, `BUILD_DIR`, `APP_PORT`, `WWW`, `EXTRA_DOMAINS`, `TWITTER_URL`,
`INSTALL_SH`) в контейнер не попадают. Для `docker-db` переменную `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`
| Ключ | Дефолт | Зачем |
|-----------------|---------|-------|
| `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` | — | отдать скрипт на `get.<domain>` (static или docker) |
Любые другие ключи в `.env` (не из этой таблицы) уходят в контейнер как переменные
окружения.
## Доступ к гиту
- Форж: 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`.
- Не разобрался — пиши админу.