← На главную
Гайды· 15.08.2026· 6 мин чтения

Запустил MCP-сервер из GitHub за 3 клика — без Dockerfile и VPS

Запускаете MCP-серверы или сайты из GitHub-репозиториев? Unyly деплоит их на свой домен без Dockerfile и VPS — пошаговая архитектура и грабли, которые сломали автора

Запустил MCP-сервер из GitHub за 3 клика — без Dockerfile и VPS
Материал подготовлен с помощью ИИ и проверен редактором

Вы нашли в каталоге MCP-сервер на 40 строк, а запустить его — это поднять VPS, написать Dockerfile, настроить Nginx и выпустить сертификат. Или было так, пока не появился Unyly: подключаете GitHub-репозиторий, получаете работающий проект на slug.unyly.org, а пуш в ветку пересобирает его автоматически. Работает для MCP-серверов на Node и Python, статики, фронтенда и Next.js. В гайде — архитектура, код генерации Dockerfile и грабли, на которых автор потерял два часа и все живые сайты.

Зачем это нужно: проблема дисбаланса усилий

MCP-серверы (Model Context Protocol) — это микро-сервисы, которые позволяют AI-ассистентам (Claude, Cursor, VS Code Copilot) взаимодействовать с кодовыми базами: читать метаданные, запускать тесты, генерировать код. Большинство из них живут не как npm-пакеты, а как GitHub-репозитории. Чтобы запустить такой сервер, нужно:

  1. Склонировать репозиторий.
  2. Установить зависимости (npm install или pip install).
  3. Собрать проект, если требуется.
  4. Запустить сервер и держать его живым.
  5. Обернуть stdio-процесс в HTTP, иначе к нему не подключатся AI-клиенты (Claude, ChatGPT).

Итог: для сервера на 40 строк человек поднимает VPS, пишет Dockerfile, настраивает Nginx, выпускает сертификат и вешает вебхук на автодеплой. Unyly решает эту проблему: подключаете репозиторий, получаете работающий проект на slug.unyly.org, а пуш в ветку пересобирает его автоматически.

Как это работает: архитектура деплой-платформы

Общая схема деплоя в Unyly — это аккуратная склейка стандартных инструментов:

  1. GitHub push → вебхук на Next.js API (с HMAC-проверкой).
  2. Запись в очередь runner_deploys (SQLite).
  3. Демон-воркер (unyly-runner-worker) берёт задачу:
  • git clone с токеном пользователя.
  • Генерация Dockerfile под тип проекта.
  • docker build и docker run с лимитами.
  • Healthcheck (для MCP-серверов — JSON-RPC initialize).
  1. Реверс-прокси (unyly-runner-proxy) на порту :3900 роутит трафик по заголовку Host → нужный контейнер.

Важная деталь: прокси и воркер — это два отдельных процесса под pm2. Объединять их в один нельзя: если воркер упадёт, он утащит за собой прокси, и все сайты лягут. Автор узнал это на практике, когда потерял пару часов и все живые сайты.

Генерация Dockerfile: пять рецептов для разных типов проектов

Пользователь Dockerfile не пишет. Если он есть в репозитории, Unyly использует его. Если нет — генерирует автоматически. Вот пять рецептов:

1. MCP-сервер на Node.js

Точка входа ищется в порядке: binmainindex.js из package.json. Ключевой момент: stdio-процесс оборачивается в `supergateway`, который превращает stdin/stdout сервера в streamable HTTP на /mcp.

``dockerfile FROM node:22-slim WORKDIR /app COPY package*.json ./ RUN npm install --omit=dev --no-audit --no-fund || npm install --no-audit --no-fund COPY . . RUN npm install -g supergateway@latest --no-audit --no-fund EXPOSE 3000 CMD ["sh", "-c", "supergateway --stateful --stdio 'node index.js' \ --outputTransport streamableHttp --port 3000 --streamableHttpPath /mcp"] ``

2. MCP-сервер на Python

Базовый образ — python:3.12-slim. Зависимости берутся из requirements.txt или pyproject.toml. supergateway (написан на Node) устанавливается через apt-get install nodejs npm. Точка входа — server.py или main.py.

``dockerfile FROM python:3.12-slim WORKDIR /app RUN apt-get update && apt-get install -y nodejs npm COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN npm install -g supergateway@latest --no-audit --no-fund EXPOSE 3000 CMD ["sh", "-c", "supergateway --stateful --stdio 'python server.py' \ --outputTransport streamableHttp --port 3000 --streamableHttpPath /mcp"] ``

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

Если в репозитории есть index.html и нет package.json, сайт раздаётся через nginx:alpine.

``dockerfile FROM nginx:alpine COPY . /usr/share/nginx/html EXPOSE 80 ``

4. Фронтенд со сборкой

Запускается npm run build, а выходная папка определяется перебором стандартных имён (dist, build, out, public).

```dockerfile FROM node:22-slim as builder WORKDIR /app COPY package*.json ./ RUN npm install --no-audit --no-fund COPY . . RUN npm run build

FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 ```

5. Next.js

Определяется по зависимости next в package.json. Запускается next start.

```dockerfile FROM node:22-slim as builder WORKDIR /app COPY package*.json ./ RUN npm install --no-audit --no-fund COPY . . RUN npm run build

FROM node:22-slim WORKDIR /app COPY --from=builder /app/.next ./.next COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json RUN npm install --omit=dev --no-audit --no-fund EXPOSE 3000 CMD ["npx", "next", "start"] ```

Запуск контейнера: жёсткие лимиты и безопасность

Собранный образ запускается с ограничениями: это чужой код на вашем железе, поэтому политика — минимум ресурсов, минимум прав.

``bash docker run -d --name <container> --restart unless-stopped \ --memory 384m --cpus 0.5 --pids-limit 256 \ --cap-drop ALL --security-opt no-new-privileges \ -p 127.0.0.1:<port>:3000 \ <image> ``

  • Порт слушается только на localhost — наружу его выставляет реверс-прокси.
  • --cap-drop ALL убирает все Linux capabilities. Исключение — nginx в сайтах: ему нужны CHOWN, SETUID, SETGID для переключения воркеров на unprivileged-пользователя. MCP-контейнеры живут без capabilities.

Healthcheck: проверка, которая реально работает

Для сайтов healthcheck — это HTTP-запрос на / (коды 2xx или 3xx). Для MCP-серверов — это JSON-RPC initialize по протоколу MCP с дедлайном 60 секунд:

``bash curl -s --max-time 5 -X POST http://127.0.0.1:<port>/mcp \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": { "name": "unyly-health", "version": "1.0" } } }' ``

Если в ответе есть "result", сервер действительно говорит на MCP. Если healthcheck не прошёл за минуту, в лог деплоя выводятся последние 40 строк docker logs — чтобы пользователь видел причину, а не просто "failed".

Роутинг по Host: как не подорваться на wildcard-поддомене

Реверс-прокси на порту :3900 смотрит на заголовок Host и выбирает контейнер: slug.unyly.org, кастомный домен или превью пулреквеста. Nginx отдаёт весь wildcard-поддомен в этот прокси, но здесь спрятана мина.

Правильный server_name — это регулярное выражение с негативным просмотром вперёд, которое исключает служебные поддомены:

``nginx server_name ~^(?!(www|app|api|admin|gateway|staging|run|mail|smtp|ftp|deploy)\.)[a-z0-9-]+\.unyly\.org$; ``

Простой *.unyly.org ставить нельзя: он перехватит трафик служебных поддоменов (app.unyly.org, api.unyly.org), и платформа сломается.

Где ломается: грабли, на которых потерял время

Если объединить прокси и воркер в один процесс под pm2, то при падении воркера упадёт и прокси, и все сайты лягут. Решение: два отдельных процесса (unyly-runner-proxy и unyly-runner-worker).

  1. Прокси и воркер в одном процессе

Простой *.unyly.org перехватывает трафик служебных поддоменов (app.unyly.org, api.unyly.org). Решение: регулярное выражение с негативным просмотром вперёд.

  1. Wildcard-поддомен в Nginx

В nginx-конфиге для SPA-фолбэка нельзя использовать $uri в try_files, потому что она содержит декодированный путь (с пробелами, %20). Решение: использовать $request_uri (не декодируется).

  1. Переменная `$uri` в Nginx

Обычный HTTP-запрос на / не гарантирует, что сервер действительно говорит на MCP. Решение: JSON-RPC initialize с дедлайном 60 секунд.

  1. Healthcheck для MCP-серверов

supergateway написан на Node, поэтому в Python-контейнерах нужно ставить nodejs и npm через apt-get. Без этого supergateway не установится, и сервер не запустится.

  1. Зависимости в MCP-серверах на Python

Что попробовать дальше

Зарегистрируйтесь на Unyly и подключите GitHub-репозиторий с MCP-сервером или сайтом. Получите работающий проект на slug.unyly.org.

  1. Подключить свой репозиторий

Включите вебхук на GitHub, чтобы пуш в ветку автоматически пересобирал проект.

  1. Настроить автодеплой

Настройте CNAME-запись на unyly.org и подключите свой домен к проекту.

  1. Добавить кастомный домен

Создайте пулреквест в репозитории — Unyly автоматически развернёт превью на отдельном поддомене.

  1. Попробовать превью пулреквестов

Архитектура Unyly открыта: GitHub-репозиторий. Можно адаптировать её для своих нужд.

  1. Изучить исходники

Источники

Материал подготовил PLai AI — редакционный ИИ PLai.

Он же отбирает источники, пишет тексты и модерирует комментарии. Работает на PLGames AI — собственном шлюзе к языковым моделям.

Читайте также

Комментарии

Пока никто не написал. Будьте первым.

Комментарии проверяет AI-модератор PLai. По существу — публикуется сразу.

Деплой MCP-серверов за 5 минут: как запустить GitHub-репо без VPS и Docker — PLai