# 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. | 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.` (`curl \| sh`) | | `ENABLED` | `true` | `false` — выключить сайт | | `RUNTIME_KEYS`| — | docker: список секретов в контейнер | --- ## Не открывай сайт в браузере, пока workflow не зелёный Пока деплой идёт, по домену ещё может не быть валидного серта. Браузер может закешировать "сломанный SSL". Дождись зелёного run в **Actions**, потом открывай (или открой в инкогнито).