Развёртывание любого проекта: полная поваренная книга

Этот документ — исчерпывающий рецептурник: у вас есть исходники проекта — здесь есть путь, как развернуть их на сервере mitdev, только по документации. Каждый рецепт самодостаточен: команды копируются как есть.

Новичок? Порядок чтения: Азбука (термины, SSH, домены) → Большое руководство (первый сервер с нуля) → эта страница (рецепт под ваш конкретный стек).

Содержание:

  1. Выбор способа запуска (дерево решений)
  2. Общая подготовка (одинакова для всех)
  3. Рецепты по типу проектаNode.js API (Express/Nest/Fastify) · Next.js · Статический сайт (React/Vue/HTML) · Python (FastAPI/Django/Flask) · Go / Rust / бинарник · PHP (Laravel/WordPress) · Любой проект с Docker Compose · Kubernetes · Фоновые воркеры и Telegram-боты
  4. Подключение к службам: строки подключения
  5. Несколько проектов на одном сервере
  6. Обновление, логи, откат
  7. Чек-лист «проект не открывается»

1. Выбор способа запуска

Ситуация Способ Рецепт
В проекте есть docker-compose.yml Docker Compose — универсально, ничего не важно про язык 3.7
Node.js без Docker PM2 3.1, 3.2
Только собранная статика (dist/build) nginx напрямую, процессов не нужно 3.3
Python/Go/Rust/PHP без Docker systemd-юнит или Docker 3.43.6
Нужна отказоустойчивость приложения Kubernetes (HA-кластер из 3 серверов) 3.8
Нет Dockerfile и не Node проще всего добавить Dockerfile (10 строк) и идти путём 3.7 3.7

Практическое правило: есть compose — используйте compose; Node без контейнеров — PM2; всё остальное стремитесь упаковать в Docker.

2. Общая подготовка

Одинакова для любого рецепта.

2.1. Сервер. Чистый сервер → curl -fsSL https://mitdev.top/get | sudo bash. Компоненты: по умолчанию (+ Docker, если пойдёте путём compose). Проверка: mitdev doctor — всё зелёное.

2.2. Домен. В DNS-панели: A-запись myapp.example.com → IP сервера. Проверка: dig +short myapp.example.com возвращает IP. Без домена можно жить (доступ по http://IP:порт), но SSL требует домен.

2.3. Доступ к репозиторию. Публичный — просто URL. Приватный:

2.4. Развёртывание каркаса. Всегда начинайте с:

sudo mitdev app

Он спросит имя, git-URL, домен, порт, nginx-конфиг — и сам сделает: клон в /home/deploy/apps/<имя>, .env из .env.example, зависимости, compose (если есть), nginx, SSL. Дальнейшие рецепты дополняют его там, где нужен процесс-менеджер.

Локальный путь как источник. В поле источника можно указать не только git-URL, но и путь к каталогу на сервере (абсолютный /srv/src/app или относительный от текущего каталога). mitdev распознаёт локальный путь автоматически и просит подтверждение. Файлы копируются в ~/apps/<name> через rsync; исходный путь запоминается. При sudo mitdev deploy <name> вместо git pull выполняется повторная синхронизация из этого пути. Серверные .env, node_modules/.venv и служебный .mitdev-run.sh при синхронизации сохраняются.

2.5. Заполните .env. Настоящие значения (строки подключения — в разделе 4):

sudo nano /home/deploy/apps/<имя>/.env

3. Рецепты

3.1. Node.js API

Express, NestJS, Fastify, Koa — любой сервер на Node.

sudo mitdev app        # имя: api, порт: тот, что слушает ваш код (например 3000)
sudo nano /home/deploy/apps/api/.env

# сборка, если есть (Nest/TypeScript):
sudo -u deploy -H bash -lc 'cd ~/apps/api && npm run build'

# запуск под PM2 (переживает перезагрузки, рестартует при падении):
sudo -u deploy -H bash -lc 'cd ~/apps/api && pm2 start npm --name api -- start && pm2 save'
# либо конкретный файл:  pm2 start dist/main.js --name api
# несколько CPU-ядер:    pm2 start dist/main.js --name api -i max   (cluster-режим)

# проверка:
sudo -u deploy -H pm2 ls
curl -s http://127.0.0.1:3000/ | head -3
curl -s https://myapp.example.com | head -3

Если в репозитории есть ecosystem.config.js — вместо pm2 start npm используйте pm2 start ecosystem.config.js.

3.2. Next.js

SSR/ISR (обычный Next):

sudo mitdev app        # порт 3000
sudo -u deploy -H bash -lc 'cd ~/apps/web && npm run build'
sudo -u deploy -H bash -lc 'cd ~/apps/web && pm2 start npm --name web -- start && pm2 save'

Статический экспорт (output: "export"): это статика — идите в 3.3 с каталогом out/.

Обновление любого Next: sudo mitdev deploy web (сам сделает pull → install → build → рестарт PM2-процесса web).

3.3. Статический сайт

React/Vue/Svelte-сборка, чистый HTML — процесс не нужен, отдаёт nginx.

sudo mitdev app        # домен укажите, порт любой (не используется), nginx: свой конфиг

На вопрос о своём nginx-конфиге дайте файл (или положите в репозиторий как .mitdev/nginx.conf):

server {
    listen 80;
    server_name __DOMAIN__;
    root /home/deploy/apps/__APP_NAME__/dist;   # ваш каталог сборки: dist/build/out
    index index.html;
    location / { try_files $uri $uri/ /index.html; }   # SPA-роутинг
    location ~* \.(js|css|png|jpg|svg|woff2)$ { expires 30d; add_header Cache-Control public; }
}

Соберите проект и перезагрузите nginx:

sudo -u deploy -H bash -lc 'cd ~/apps/site && npm run build'
sudo mitdev nginx reload

3.4. Python

FastAPI/Flask (uvicorn/gunicorn) или Django. mitdev не ставит Python-стек модулем, поэтому два пути.

Путь А (рекомендуется) — Docker. Добавьте в проект Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

и docker-compose.yml:

services:
  app:
    build: .
    restart: unless-stopped
    env_file: .env
    ports: ["8000:8000"]

Дальше — обычный sudo mitdev app (порт 8000): compose поднимется сам.

Путь Б — systemd без Docker:

sudo apt install -y python3-venv
sudo -u deploy -H bash -lc 'cd ~/apps/api && python3 -m venv .venv && .venv/bin/pip install -r requirements.txt'

sudo tee /etc/systemd/system/myapi.service <<'EOF'
[Unit]
Description=myapi
After=network.target
[Service]
User=deploy
WorkingDirectory=/home/deploy/apps/api
EnvironmentFile=/home/deploy/apps/api/.env
ExecStart=/home/deploy/apps/api/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now myapi

Django: ExecStart=….venv/bin/gunicorn config.wsgi -b 127.0.0.1:8000; статику отдайте nginx'ом (alias на staticfiles/ в своём конфиге), миграции — .venv/bin/python manage.py migrate перед стартом.

3.5. Go / Rust / бинарник

sudo mitdev app        # клон + nginx; порт — какой слушает бинарник
# сборка:
sudo -u deploy -H bash -lc 'cd ~/apps/svc && go build -o svc ./cmd/svc'   # или cargo build --release

sudo tee /etc/systemd/system/svc.service <<'EOF'
[Unit]
Description=svc
After=network.target
[Service]
User=deploy
WorkingDirectory=/home/deploy/apps/svc
EnvironmentFile=/home/deploy/apps/svc/.env
ExecStart=/home/deploy/apps/svc/svc
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now svc

3.6. PHP

Laravel/WordPress — самый надёжный путь на mitdev-сервере — Docker (php-fpm не ставится модулем). Для Laravel добавьте compose с officially поддерживаемым образом (или Laravel Sail: php artisan sail:install); для WordPress — стандартный compose из документации WordPress (wordpress + mysql). Дальше — sudo mitdev app, порт — опубликованный в compose. Nginx mitdev проксирует на контейнер, SSL — как обычно.

3.7. Docker Compose

Универсальный путь для ЛЮБОГО проекта. Требование одно: в корне репозитория docker-compose.yml (или compose.yml), где веб-сервис публикует порт:

services:
  app:
    build: .
    restart: unless-stopped      # обязательно: авто-старт после перезагрузки
    env_file: .env
    ports: ["3000:3000"]         # левый порт = порт для mitdev app
sudo mitdev app                  # порт: 3000 (левый из ports)
sudo nano /home/deploy/apps/<имя>/.env
cd /home/deploy/apps/<имя> && sudo docker compose up -d   # если правили .env после

Управление: mitdev docker ps, mitdev docker logs <контейнер>, cd ~/apps/<имя> && docker compose restart.

База в compose или на хосте? Если проект несёт свою БД в compose — оставьте как есть (данные — в named volume). Если хотите центральную/ кластерную БД mitdev — уберите сервис БД из compose и дайте приложению строку подключения из раздела 4; контейнеру для доступа к БД хоста используйте host.docker.internal c extra_hosts: ["host.docker.internal:host-gateway"].

3.8. Kubernetes

Когда нужен HA (переживать смерть сервера) или десятки реплик.

# образ должен лежать в registry (GitHub Actions → ghcr.io — стандартный путь)
sudo mitdev k8s deploy myapp ghcr.io/you/myapp:latest 3000 myapp.example.com

Всё остальное (Deployment с probes, анти-аффинити по серверам, Service, публикация, SSL) mitdev делает сам. Кластер из трёх серверов: режимы init/join в инсталляторе + mitdev k8s token — см. COMMANDS.md. Секреты: положите .env в кластер один раз — kubectl create secret generic myapp-env --from-env-file=.env, и добавьте в свой манифест envFrom: secretRef.

3.9. Воркеры и боты

Процессы без входящего HTTP (очереди, кроны, Telegram-боты): домен и nginx не нужны — на вопросы mitdev app о домене ответьте «пусто».

sudo mitdev app                   # домен: пусто
# Node-воркер:
sudo -u deploy -H bash -lc 'cd ~/apps/bot && pm2 start src/bot.js --name bot && pm2 save'
# не-Node — systemd-юнит из рецепта 3.5, либо compose без ports.

Расписание (аналог cron): pm2 start job.js --name job --cron "0 3 * * *" --no-autorestart, либо системный /etc/cron.d/.

4. Строки подключения

Все пароли служб созданы при установке и лежат в /root/.mitdev-credentials (sudo cat /root/.mitdev-credentials). Подставляйте в .env проекта:

Служба Строка подключения / переменные
PostgreSQL (этот же сервер) postgresql://<user>:<пароль postgresql>@127.0.0.1:5432/<база>
PostgreSQL-кластер через прокси postgresql://<user>:<пароль>@127.0.0.1:5432/<база>?sslmode=require (после mitdev pg proxy A B C на этом сервере)
PostgreSQL-кластер через VIP postgresql://<user>:<пароль>@<VIP>:5432/<база>?sslmode=require
Redis redis://:<пароль redis>@127.0.0.1:6379/0
MongoDB mongodb://127.0.0.1:27017/<база> (auth включаете сами — см. SECURITY.md)
RabbitMQ amqp://admin:<пароль rabbitmq>@127.0.0.1:5672/ (консоль: :15672)
MinIO (S3) endpoint http://127.0.0.1:9000, AWS_ACCESS_KEY_ID=<root_user>, AWS_SECRET_ACCESS_KEY=<root_password>

Приложение на другом сервере, а БД здесь? На каждом DB-узле: sudo mitdev pg allow <IP-приложения> <база> <user> — и в строке вместо 127.0.0.1 адрес DB-сервера (или VIP/прокси). Для Redis/Mongo/RabbitMQ наружу по умолчанию закрыто — открывайте осознанно (sudo mitdev firewall allow … + bind в конфиге службы) или туннелируйте.

5. Несколько проектов

Сколько угодно приложений на одном сервере — уникальные имя и порт:

sudo mitdev app   # api,  api.example.com,  порт 3000
sudo mitdev app   # admin, admin.example.com, порт 3001
sudo mitdev app   # bot,  без домена,       порт не важен

Каждому — свой nginx-сайт и свой SSL-сертификат (автоматически). Поддомены: просто ещё A-записи на тот же IP. Один домен, разные пути (/api → :3000, / → статика) — случай для своего nginx-конфига (рецепт 3.3

6. Обновление, логи, откат

sudo mitdev deploy <имя>     # git pull → зависимости → build → рестарт (PM2/compose)

Для systemd-рецептов после deploy добавьте рестарт юнита: sudo systemctl restart <юнит>.

Логи:

sudo -u deploy -H pm2 logs <имя> --lines 100    # PM2
mitdev docker logs <контейнер>                  # Docker
sudo journalctl -u <юнит> -n 100 -f             # systemd
mitdev k8s logs <имя>                           # Kubernetes
tail -f /var/log/nginx/<имя>.access.log         # HTTP-трафик

Откат на прошлый коммит:

sudo -u deploy -H git -C /home/deploy/apps/<имя> log --oneline -5
sudo -u deploy -H git -C /home/deploy/apps/<имя> reset --hard <коммит>
sudo mitdev deploy <имя>   # пересборка/рестарт уже от старого кода

Бекапы перед рискованными обновлениями: sudo mitdev backup.

7. Чек-лист

Проект не открывается — идите сверху вниз, где сломалось — там и чините:

# 1. Процесс жив и слушает свой порт?
sudo -u deploy -H pm2 ls                        # или docker compose ps / systemctl status
sudo ss -tlnp | grep <порт>

# 2. Отвечает локально?
curl -sv http://127.0.0.1:<порт>/ | head        # ошибка здесь = смотрите логи приложения (.env? миграции?)

# 3. Nginx знает про домен и жив?
sudo nginx -t && ls /etc/nginx/sites-enabled/
curl -sv -H "Host: myapp.example.com" http://127.0.0.1/ | head

# 4. DNS указывает сюда?
dig +short myapp.example.com                    # = IP сервера?

# 5. Снаружи пускает файрвол?
mitdev firewall status                          # 80,443 открыты?

# 6. SSL?
curl -sv https://myapp.example.com 2>&1 | grep -E 'SSL|HTTP'
sudo certbot certificates

Типовые причины по частоте: незаполненный .env (№1 с большим отрывом); порт в mitdev app не совпадает с портом приложения; не выполнены миграции БД; DNS ещё не обновился (до часа); приложение слушает 127.0.0.1 внутри Docker (нужно 0.0.0.0). Остальное — TROUBLESHOOTING.md.