{"id":491009,"date":"2026-08-15T03:09:50","date_gmt":"2026-08-15T03:09:50","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=491009"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=491009","title":{"rendered":"\u0414\u0435\u043f\u043b\u043e\u0439-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0441\u0430\u0439\u0442\u043e\u0432, \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/46a\/147\/78a\/46a14778aed4c54404b8c35cc86195f5.png\" width=\"2400\" height=\"1260\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/46a\/147\/78a\/46a14778aed4c54404b8c35cc86195f5.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/46a\/147\/78a\/46a14778aed4c54404b8c35cc86195f5.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u043f\u0438\u0441\u0430\u043b \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432: 80 \u0442\u044b\u0441\u044f\u0447 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0434\u0435\u0432\u044f\u0442\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u0435. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0438 \u0432 \u043b\u0438\u0447\u043a\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u0441\u043f\u043b\u044b\u043b \u0432\u043e\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0441\u0430\u043c \u043d\u0435 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043b, \u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433: \u00ab\u043d\u0430\u0448\u0451\u043b \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0435\u0433\u043e \u0433\u0434\u0435?\u00bb<\/p>\n<p>\u0421 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0431\u0435\u0434\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u043e\u0431\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0436\u0438\u0432\u0451\u0442 \u043d\u0435 \u043a\u0430\u043a \u0433\u043e\u0442\u043e\u0432\u044b\u0439 npm-\u043f\u0430\u043a\u0435\u0442, \u0430 \u043a\u0430\u043a \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 GitHub. \u0415\u0433\u043e \u043d\u0430\u0434\u043e \u0441\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0441\u043e\u0431\u0440\u0430\u0442\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0436\u0438\u0432\u044b\u043c. \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 stdio (\u0430 \u0442\u0430\u043a\u0438\u0445 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e), \u0441\u0432\u0435\u0440\u0445\u0443 \u0435\u0449\u0451 \u0437\u0430\u0434\u0430\u0447\u0430 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 HTTP, \u0438\u043d\u0430\u0447\u0435 \u043a \u043d\u0435\u043c\u0443 \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u043d\u0438 <a href=\"http:\/\/claude.ai\" rel=\"noopener noreferrer nofollow\">claude.ai<\/a>, \u043d\u0438 ChatGPT. \u0418\u0442\u043e\u0433: \u043f\u043e\u0434 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 40 \u0441\u0442\u0440\u043e\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 VPS, \u043f\u0438\u0448\u0435\u0442 Dockerfile, \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 nginx, \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0438 \u0432\u0435\u0448\u0430\u0435\u0442 \u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 \u0430\u0432\u0442\u043e\u0434\u0435\u043f\u043b\u043e\u0439. \u0414\u0438\u0437\u0431\u0430\u043b\u0430\u043d\u0441 \u0443\u0441\u0438\u043b\u0438\u0439 \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u044b\u0439.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0432\u043d\u0443\u0442\u0440\u0438 Unyly \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0434\u0435\u043f\u043b\u043e\u044f. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0448\u044c GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0448\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 <a href=\"http:\/\/slug.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>slug.unyly.org<\/code><\/a>, \u043f\u0443\u0448 \u0432 \u0432\u0435\u0442\u043a\u0443 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0435\u0433\u043e \u0441\u0430\u043c. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 (\u0441\u0442\u0430\u0442\u0438\u043a\u0430, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u0441\u0431\u043e\u0440\u043a\u0438, Next.js), \u0438 \u0434\u043b\u044f MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 Node \u0438 Python. \u041d\u0438\u0436\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043f\u043e \u0441\u043b\u043e\u044f\u043c \u0438 \u0447\u0435\u0441\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044e \u0433\u0440\u0430\u0431\u043b\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0442\u0435\u0440\u044f\u043b \u0432\u0440\u0435\u043c\u044f. \u041a\u043e\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1c9\/a2e\/aeb\/1c9a2eaeb5cb818292100f5ec5369c70.png\" alt=\"\u0418\u0437 GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\" width=\"2880\" height=\"1900\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/1c9\/a2e\/aeb\/1c9a2eaeb5cb818292100f5ec5369c70.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1c9\/a2e\/aeb\/1c9a2eaeb5cb818292100f5ec5369c70.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0418\u0437 GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442<\/figcaption><\/div>\n<\/figure>\n<h3>\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430<\/h3>\n<p>\u041d\u0438\u0447\u0435\u0433\u043e \u044d\u043a\u0437\u043e\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e, \u0432\u0441\u044f \u0441\u0443\u0442\u044c \u0432 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043a\u043b\u0435\u0439\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043a\u0438\u0440\u043f\u0438\u0447\u0435\u0439. \u041f\u043e\u0442\u043e\u043a \u0442\u0430\u043a\u043e\u0439:<\/p>\n<pre><code>GitHub push   -&gt; \u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 Next.js API (HMAC-\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430)   -&gt; \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c runner_deploys (SQLite)   -&gt; \u0434\u0435\u043c\u043e\u043d-\u0432\u043e\u0440\u043a\u0435\u0440 \u0431\u0435\u0440\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443        git clone \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u044e\u0437\u0435\u0440\u0430        \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Dockerfile \u043f\u043e\u0434 \u0442\u0438\u043f \u043f\u0440\u043e\u0435\u043a\u0442\u0430        docker build        docker run \u0441 \u043b\u0438\u043c\u0438\u0442\u0430\u043c\u0438        healthcheck   -&gt; \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u043d\u0430 :3900 \u0440\u043e\u0443\u0442\u0438\u0442 \u043f\u043e Host -&gt; \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c, \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0434\u043e\u0448\u0451\u043b \u043d\u0435 \u0441\u0440\u0430\u0437\u0443: \u043f\u0440\u043e\u043a\u0441\u0438 \u0438 \u0432\u043e\u0440\u043a\u0435\u0440 \u044d\u0442\u043e <strong>\u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430<\/strong> \u043f\u043e\u0434 pm2 (<code>unyly-runner-proxy<\/code> \u0438 <code>unyly-runner-worker<\/code>), \u0430 \u043d\u0435 \u043e\u0434\u0438\u043d. \u041f\u043e\u0447\u0435\u043c\u0443, \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e \u0433\u0440\u0430\u0431\u043b\u0438, \u0442\u0430\u043c \u044d\u0442\u043e \u0441\u0442\u043e\u0438\u043b\u043e \u043c\u043d\u0435 \u043f\u0430\u0440\u044b \u0447\u0430\u0441\u043e\u0432 \u0438 \u0432\u0441\u0435\u0445 \u0436\u0438\u0432\u044b\u0445 \u0441\u0430\u0439\u0442\u043e\u0432.<\/p>\n<h3>\u0421\u043b\u043e\u0439 1. \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Dockerfile<\/h3>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c Dockerfile \u043d\u0435 \u043f\u0438\u0448\u0435\u0442. \u0415\u0441\u043b\u0438 \u043e\u043d \u0435\u0441\u0442\u044c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u044f \u0443\u0432\u0430\u0436\u0430\u044e \u0435\u0433\u043e \u0438 \u0431\u0435\u0440\u0443 \u043a\u0430\u043a \u0435\u0441\u0442\u044c. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e \u0441\u0430\u043c \u043f\u043e \u0442\u0438\u043f\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041f\u044f\u0442\u044c \u0440\u0435\u0446\u0435\u043f\u0442\u043e\u0432.<\/p>\n<p><strong>MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Node.<\/strong> \u0422\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0438\u0449\u0443 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 <code>bin<\/code> &gt; <code>main<\/code> &gt; <code>index.js<\/code> \u0438\u0437 <code>package.json<\/code>. \u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: stdio-\u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 <code>supergateway<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 stdin\/stdout \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 streamable HTTP \u043d\u0430 <code>\/mcp<\/code>. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.<\/p>\n<pre><code>FROM node:22-slimWORKDIR \/appCOPY package*.json .\/RUN npm install --omit=dev --no-audit --no-fund || npm install --no-audit --no-fundCOPY . .RUN npm install -g supergateway@latest --no-audit --no-fundEXPOSE 3000CMD [\"sh\", \"-c\", \"supergateway --stateful --stdio 'node index.js' \\     --outputTransport streamableHttp --port 3000 --streamableHttpPath \/mcp\"]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Python.<\/strong> \u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 <code>python:3.12-slim<\/code>, \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 <code>requirements.txt<\/code> \u0438\u043b\u0438 <code>pyproject.toml<\/code>, \u0430 <code>supergateway<\/code> (\u043e\u043d \u043d\u0430 Node) \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u0447\u0435\u0440\u0435\u0437 <code>apt-get install nodejs npm<\/code>. \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 <a href=\"http:\/\/server.py\" rel=\"noopener noreferrer nofollow\"><code>server.py<\/code><\/a> \u0438\u043b\u0438 <a href=\"http:\/\/main.py\" rel=\"noopener noreferrer nofollow\"><code>main.py<\/code><\/a>.<\/p>\n<p><strong>\u0421\u0430\u0439\u0442, \u0442\u0440\u0438 \u0440\u0435\u0446\u0435\u043f\u0442\u0430 \u043a\u0430\u043a \u0443 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0435\u043f\u043b\u043e\u0439-\u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0430:<\/strong><\/p>\n<ol>\n<li>\n<p>\u0427\u0438\u0441\u0442\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u043a\u0430 (\u0435\u0441\u0442\u044c <code>index.html<\/code>, \u043d\u0435\u0442 <code>package.json<\/code>) \u0435\u0434\u0435\u0442 \u0432 <code>nginx:alpine<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0441\u043e \u0441\u0431\u043e\u0440\u043a\u043e\u0439: \u0433\u043e\u043d\u044f\u044e <code>npm run build<\/code> \u0438 \u0440\u0430\u0437\u0434\u0430\u044e \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u0448\u043b\u043e\u0441\u044c. \u0422\u0443\u0442 \u0437\u0430\u0431\u0430\u0432\u043d\u044b\u0439 \u043a\u0443\u0441\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0432\u044b\u0445\u043e\u0434\u043d\u0443\u044e \u043f\u0430\u043f\u043a\u0443 \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u043e\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0438\u043c\u0451\u043d:<\/p>\n<\/li>\n<\/ol>\n<pre><code>RUN for d in dist build out public .; do \\      if [ -f \"$d\/index.html\" ]; then cp -r \"$d\" \/site &amp;&amp; break; fi; \\    done &amp;&amp; test -f \/site\/index.html<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ol start=\"3\">\n<li>\n<p>Next.js \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e \u043f\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 <code>next<\/code> \u0432 <code>package.json<\/code> \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e <code>next start<\/code> \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u043e\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 nginx-\u043a\u043e\u043d\u0444\u0438\u0433 \u0441 SPA-\u0444\u043e\u043b\u0431\u044d\u043a\u043e\u043c \u043b\u0435\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>COPY<\/code>, \u0430 \u043d\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 <code>RUN<\/code>. \u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a, \u0442\u043e\u0436\u0435 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445, \u0442\u0430\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043f\u0440\u043e <code>$uri<\/code>.<\/p>\n<h3>\u0421\u043b\u043e\u0439 2. \u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430<\/h3>\n<p>\u0421\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441 \u0436\u0451\u0441\u0442\u043a\u0438\u043c\u0438 \u043b\u0438\u043c\u0438\u0442\u0430\u043c\u0438. \u042d\u0442\u043e \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043c\u043e\u0451\u043c \u0436\u0435\u043b\u0435\u0437\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043f\u0440\u0430\u0432.<\/p>\n<pre><code class=\"bash\">docker run -d --name &lt;container&gt; --restart unless-stopped \\  --memory 384m --cpus 0.5 --pids-limit 256 \\  --cap-drop ALL --security-opt no-new-privileges \\  -p 127.0.0.1:&lt;port&gt;:3000 \\  &lt;image&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0440\u0442 \u0441\u043b\u0443\u0448\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 <a href=\"http:\/\/localhost\" rel=\"noopener noreferrer nofollow\">localhost<\/a>, \u043d\u0430\u0440\u0443\u0436\u0443 \u0435\u0433\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438. <code>--cap-drop ALL<\/code> \u0443\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0435 \u043b\u0438\u043d\u0443\u043a\u0441\u043e\u0432\u044b\u0435 capabilities. \u041e\u0434\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: nginx \u0432 site-\u043e\u0431\u0440\u0430\u0437\u0430\u0445 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u0431\u0435\u0437 <code>CHOWN<\/code>, <code>SETUID<\/code>, <code>SETGID<\/code> (\u0435\u043c\u0443 \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440\u044b \u043d\u0430 unprivileged-\u044e\u0437\u0435\u0440\u0430), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0438\u043c \u0442\u0440\u0451\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c \u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0445. MCP-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0436\u0438\u0432\u0443\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437 capabilities.<\/p>\n<h3>\u0421\u043b\u043e\u0439 3. Healthcheck, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442<\/h3>\n<p>\u0412\u043e\u0442 \u0442\u0443\u0442 \u044f \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u0445\u043e\u0442\u0435\u043b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u00ab\u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0434\u043d\u044f\u043b\u0441\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 \u0436\u0438\u0432\u043e\u0439\u00bb. \u0414\u043b\u044f \u0441\u0430\u0439\u0442\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: HTTP-\u043a\u043e\u0434 2xx \u0438\u043b\u0438 3xx \u043d\u0430 <code>\/<\/code>. \u0410 \u0432\u043e\u0442 \u0434\u043b\u044f MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 healthcheck \u044d\u0442\u043e <strong>\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 JSON-RPC <\/strong><code><strong>initialize<\/strong><\/code><strong> \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 MCP<\/strong>, \u0441 \u0434\u0435\u0434\u043b\u0430\u0439\u043d\u043e\u043c 60 \u0441\u0435\u043a\u0443\u043d\u0434:<\/p>\n<pre><code class=\"bash\">curl -s --max-time 5 -X POST http:\/\/127.0.0.1:&lt;port&gt;\/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\"}}}'<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0435\u0441\u0442\u044c <code>\"result\"<\/code>, \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043d\u0430 MCP, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u043b \u043f\u043e\u0440\u0442. \u041d\u0435 \u043f\u0440\u043e\u0448\u0451\u043b \u0437\u0430 \u043c\u0438\u043d\u0443\u0442\u0443: \u0442\u044f\u043d\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 40 \u0441\u0442\u0440\u043e\u043a <code>docker logs<\/code> \u043f\u0440\u044f\u043c\u043e \u0432 \u043b\u043e\u0433 \u0434\u0435\u043f\u043b\u043e\u044f, \u0447\u0442\u043e\u0431\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0432 \u043a\u0430\u0431\u0438\u043d\u0435\u0442\u0435 \u0432\u0438\u0434\u0435\u043b \u043f\u0440\u0438\u0447\u0438\u043d\u0443, \u0430 \u043d\u0435 \u00abfailed\u00bb.<\/p>\n<h3>\u0421\u043b\u043e\u0439 4. \u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u043f\u043e Host \u0438 nginx-\u0440\u0435\u0433\u044d\u043a\u0441\u043f<\/h3>\n<p>\u0420\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u043d\u0430 <code>:3900<\/code> \u0441\u043c\u043e\u0442\u0440\u0438\u0442 \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <code>Host<\/code> \u0438 \u043f\u043e \u043d\u0435\u043c\u0443 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440: <a href=\"http:\/\/slug.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>slug.unyly.org<\/code><\/a>, \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d \u0438\u043b\u0438 \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430. nginx \u043e\u0442\u0434\u0430\u0451\u0442 \u0432\u0435\u0441\u044c wildcard-\u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d \u0432 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u043a\u0441\u0438. \u0418 \u0432\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u0430 \u043c\u0438\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u043f\u043e\u0434\u043e\u0440\u0432\u0430\u043b\u0441\u044f (\u0434\u0435\u0442\u0430\u043b\u0438 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445). \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 <code>server_name<\/code> \u044d\u0442\u043e \u0440\u0435\u0433\u044d\u043a\u0441\u043f \u0441 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u043e\u043c \u0432\u043f\u0435\u0440\u0451\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u044b:<\/p>\n<pre><code class=\"nginx\">server_name ~^(?!(www|app|api|admin|gateway|staging|run|mail|smtp|ftp|deploy)\\.)[a-z0-9-]+\\.unyly\\.org$;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u00ab\u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d, \u043a\u0440\u043e\u043c\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445\u00bb. \u041f\u0440\u043e\u0441\u0442\u043e\u0439 <code>*.<\/code><a href=\"http:\/\/unyly.org\" rel=\"noopener noreferrer nofollow\"><code>unyly.org<\/code><\/a> \u0442\u0443\u0442 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<h3>\u0421\u043b\u043e\u0439 5. \u0410\u0432\u0442\u043e\u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u043e\u0432<\/h3>\n<p>\u041f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u044f \u0432\u0435\u0448\u0430\u044e GitHub-\u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>push<\/code> \u0438 <code>pull_request<\/code>. \u041f\u043e\u0434\u043f\u0438\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e \u0447\u0435\u0441\u0442\u043d\u043e, <code>X-Hub-Signature-256<\/code>, HMAC-SHA256 \u043e\u0442 \u0441\u044b\u0440\u043e\u0433\u043e \u0442\u0435\u043b\u0430:<\/p>\n<pre><code>const expected = 'sha256=' + createHmac('sha256', project.webhook_secret).update(raw).digest('hex')\/\/ \u0434\u0430\u043b\u0435\u0435 timingSafeEqual, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0435\u0447\u044c \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Push \u0432 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043a\u043b\u0430\u0434\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0434\u0435\u043f\u043b\u043e\u0435\u0432 \u0438 \u043b\u043e\u0433\u0438 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u0430\u0431\u0438\u043d\u0435\u0442\u0435. \u0421 \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435: \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 PR \u044f \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u044e <strong>\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442-\u043f\u0440\u0435\u0432\u044c\u044e<\/strong> \u0441\u043e \u0441\u0432\u043e\u0438\u043c \u0441\u043b\u0430\u0433\u043e\u043c (<code>parent_id<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u043f\u043b\u044e\u0441 <code>pr_number<\/code>), \u0431\u0438\u043b\u0436\u0443 \u0432\u0435\u0442\u043a\u0443 PR \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442. \u0417\u0430\u043a\u0440\u044b\u043b\u0438 PR, \u043f\u0440\u0435\u0432\u044c\u044e \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u043e. \u0424\u043e\u0440\u043a-\u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u044b \u043d\u0435 \u0431\u0438\u043b\u0436\u0443, \u0442\u0430\u043c \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434 \u0441 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0441\u0435\u043a\u0440\u0435\u0442\u0430\u043c, \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e.<\/p>\n<h3>\u0427\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435<\/h3>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f21\/c46\/48f\/f21c4648f4fa1fc5c0986ecc91a38cad.png\" alt=\"\u041a\u043e\u043d\u0441\u043e\u043b\u044c \u0438 \u0442\u0438\u043f\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432\" width=\"2880\" height=\"1520\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/f21\/c46\/48f\/f21c4648f4fa1fc5c0986ecc91a38cad.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f21\/c46\/48f\/f21c4648f4fa1fc5c0986ecc91a38cad.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041a\u043e\u043d\u0441\u043e\u043b\u044c \u0438 \u0442\u0438\u043f\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432<\/figcaption><\/div>\n<\/figure>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u043e \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d <a href=\"http:\/\/deploy.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>deploy.unyly.org<\/code><\/a>: \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0434\u0435\u043f\u043b\u043e\u0438 \u0441 \u043b\u043e\u0433\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438, runtime-\u043b\u043e\u0433\u0438, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 CPU \u0438 RAM, \u0433\u0440\u0430\u0444\u0438\u043a \u0442\u0440\u0430\u0444\u0438\u043a\u0430, \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0434\u043e\u043c\u0435\u043d\u044b, \u043e\u0442\u043a\u0430\u0442\u044b. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0431\u044b\u043b\u0430 \u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u044d\u0442\u043e\u0439 \u043a\u043e\u043d\u0441\u043e\u043b\u0438, \u043e \u043d\u0435\u0439 \u043d\u0438\u0436\u0435 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445.<\/p>\n<p>\u0422\u0430\u0440\u0438\u0444\u043d\u043e \u0434\u0435\u043f\u043b\u043e\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u0432 \u043e\u0431\u0449\u0443\u044e \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 Unyly, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043e\u0440\u043e\u0431\u043a\u043e\u0439: \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u0430 Pro \u0434\u0435\u0441\u044f\u0442\u044c \u043f\u043b\u044e\u0441 \u043f\u0440\u0435\u0432\u044c\u044e PR \u0438 \u0441\u0432\u043e\u0438 \u0434\u043e\u043c\u0435\u043d\u044b.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a3\/0ba\/435\/6a30ba435cd6ac6e93fa502aa69f70ea.png\" alt=\"Deploy \u0432 \u0442\u0430\u0440\u0438\u0444\u0430\u0445\" width=\"2880\" height=\"1960\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/6a3\/0ba\/435\/6a30ba435cd6ac6e93fa502aa69f70ea.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a3\/0ba\/435\/6a30ba435cd6ac6e93fa502aa69f70ea.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>Deploy \u0432 \u0442\u0430\u0440\u0438\u0444\u0430\u0445<\/figcaption><\/div>\n<\/figure>\n<p>\u0416\u0438\u0432\u043e\u0439 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"http:\/\/hello.unyly.org\" rel=\"noopener noreferrer nofollow\">hello.unyly.org<\/a>: \u043e\u0434\u0438\u043d <code>index.html<\/code>, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u043f\u0443\u0448 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/40a\/391\/d7d\/40a391d7d704325760bef2b69dea6a0c.png\" alt=\"\u0421\u0430\u0439\u0442, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\" width=\"2400\" height=\"1520\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/40a\/391\/d7d\/40a391d7d704325760bef2b69dea6a0c.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/40a\/391\/d7d\/40a391d7d704325760bef2b69dea6a0c.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0430\u0439\u0442, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u044f \u0437\u0430\u0434\u043e\u043b\u0431\u0430\u043b\u0441\u044f, \u043d\u043e \u0441\u0434\u0435\u043b\u0430\u043b \u0432\u0441\u0435 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0440\u0435\u043d\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f, \u0441\u0442\u043e\u0438\u0442 \u043d\u0430 \u043f\u0430\u0443\u0437\u0435, \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0441\u043d\u0430 \u0438\u043b\u0438 \u0441\u043b\u0430\u0433\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442: \u0432\u0435\u0437\u0434\u0435 \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u044b\u0439 \u0435\u0434\u0438\u043d\u043e\u0440\u043e\u0433 \u0438 \u0432\u043d\u044f\u0442\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0432\u043c\u0435\u0441\u0442\u043e \u0433\u043e\u043b\u043e\u0433\u043e nginx-\u043d\u043e\u0433\u043e <code>404 Not Found<\/code>. \u0414\u0430\u0436\u0435 \u0444\u0430\u0432\u0438\u043a\u043e\u043d\u043a\u0443, \u0435\u0441\u043b\u0438 \u0443 \u0441\u0430\u0439\u0442\u0430 \u0441\u0432\u043e\u0435\u0439 \u043d\u0435\u0442, \u043e\u0442\u0434\u0430\u044e \u0435\u0434\u0438\u043d\u043e\u0440\u043e\u0433\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0441\u0438\u0440\u043e\u0442\u043e\u0439.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a3e\/71d\/96d\/a3e71d96d2501e8dc23efb7af9180a22.png\" alt=\"\u0411\u0440\u0435\u043d\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0443\u0441-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\" width=\"2400\" height=\"1600\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a3e\/71d\/96d\/a3e71d96d2501e8dc23efb7af9180a22.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a3e\/71d\/96d\/a3e71d96d2501e8dc23efb7af9180a22.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0411\u0440\u0435\u043d\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0443\u0441-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430<\/figcaption><\/div>\n<\/figure>\n<h3>\u0413\u0440\u0430\u0431\u043b\u0438, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u044b\u0447\u043d\u043e \u0438 \u0447\u0438\u0442\u0430\u044e\u0442<\/h3>\n<p><strong>\u0411\u0438\u043b\u0434 \u0433\u043b\u0443\u0448\u0438\u043b \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u0441\u0435 \u0441\u0430\u0439\u0442\u044b.<\/strong> \u041f\u0440\u043e\u043a\u0441\u0438 \u0438 \u0432\u043e\u0440\u043a\u0435\u0440 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0436\u0438\u043b\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c node-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435. \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 <code>docker build<\/code> \u0447\u0435\u0440\u0435\u0437 <code>execFileSync<\/code> \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b event loop \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u041f\u043e\u043a\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442 (\u0430 \u044d\u0442\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0441\u0435\u043a\u0443\u043d\u0434), \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442, \u0438 <strong>\u0432\u0441\u0435<\/strong> \u0440\u0430\u043d\u043d\u0435\u0440-\u0441\u0430\u0439\u0442\u044b \u0440\u0430\u0437\u043e\u043c \u043e\u0442\u0434\u0430\u044e\u0442 502. \u0420\u0430\u0437\u0432\u0451\u043b \u043d\u0430 \u0434\u0432\u0430 pm2-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u0440\u043e\u043b\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c. \u0417\u0430\u0434\u043d\u0438\u043c \u0447\u0438\u0441\u043b\u043e\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0435 \u043d\u0435\u0442.<\/p>\n<p><code><strong>printf<\/strong><\/code><strong> \u0432 Dockerfile \u043b\u043e\u043c\u0430\u043b nginx.<\/strong> SPA-\u0444\u043e\u043b\u0431\u044d\u043a \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b \u043f\u0440\u044f\u043c\u043e \u0432 <code>RUN<\/code> \u0447\u0435\u0440\u0435\u0437 <code>printf<\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 <code>try_files $uri $uri\/ \/index.html<\/code>, \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>$uri<\/code> \u0441\u044a\u0435\u0434\u0430\u043b \u0448\u0435\u043b\u043b \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u043a\u0438. \u041f\u043e\u043b\u0443\u0447\u0430\u043b\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433 \u0431\u0435\u0437 <code>$uri<\/code>, nginx \u0443\u0445\u043e\u0434\u0438\u043b \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442-\u0446\u0438\u043a\u043b, \u043e\u0442\u0434\u0430\u0432\u0430\u043b 500. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043a\u043e\u043d\u0444\u0438\u0433 \u043b\u0435\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 <code>COPY<\/code>, \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p><strong>Wildcard-\u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0430\u0434\u043c\u0438\u043d\u043a\u0443.<\/strong> \u0421\u0430\u043c\u0430\u044f \u044d\u043f\u0438\u0447\u043d\u0430\u044f. \u041f\u043e\u0432\u0435\u0441\u0438\u043b \u043d\u0430 \u043f\u0440\u043e\u043a\u0441\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432 <code>*.<\/code><a href=\"http:\/\/unyly.org\" rel=\"noopener noreferrer nofollow\"><code>unyly.org<\/code><\/a> \u0438 \u043e\u043d \u0440\u0430\u0434\u043e\u0441\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u043b <a href=\"http:\/\/admin.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>admin.unyly.org<\/code><\/a> \u0438 <a href=\"http:\/\/gateway.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>gateway.unyly.org<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0434\u0440\u0443\u0433\u043e\u043c server-\u0431\u043b\u043e\u043a\u0435. \u0410\u0434\u043c\u0438\u043d\u043a\u0430 \u043b\u0435\u0433\u043b\u0430 \u0441 \u00abnot found\u00bb, \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043e\u0442 \u043a\u043e\u043b\u043b\u0435\u0433\u0438 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e \u00ab\u0431\u0440\u043e \u0432\u0442\u0444\u00bb. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0433\u044d\u043a\u0441\u043f \u0441 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u043e\u043c \u0432\u043f\u0435\u0440\u0451\u0434 (\u0441\u043c. \u0441\u043b\u043e\u0439 4), \u0438 <code>default_server<\/code> \u043d\u0430 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u043a\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u0436\u0435 \u043d\u0435\u043b\u044c\u0437\u044f, \u0438\u043d\u0430\u0447\u0435 \u043e\u043d \u043d\u0430\u0447\u043d\u0451\u0442 \u043b\u043e\u0432\u0438\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0435.<\/p>\n<p><strong>\u041a\u0443\u043a\u0438 \u043d\u0435 \u0445\u043e\u0434\u044f\u0442 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438.<\/strong> \u041a\u043e\u043d\u0441\u043e\u043b\u044c \u043d\u0430 <a href=\"http:\/\/deploy.unyly.org\" rel=\"noopener noreferrer nofollow\"><code>deploy.unyly.org<\/code><\/a>, \u0430 \u0441\u0435\u0441\u0441\u0438\u044f \u0443 \u043c\u0435\u043d\u044f host-only \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043e\u043c\u0435\u043d\u0435. Cross-subdomain \u043a\u0443\u043a\u0438 \u044f \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u044e: Brave \u0438 Safari \u0441 \u0438\u0445 \u0442\u0440\u0435\u043a\u0438\u043d\u0433-\u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u0440\u043e\u043d\u044f\u044e\u0442 \u043d\u0430 \u043d\u0438\u0445 OAuth. \u041f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c SSO-\u043c\u043e\u0441\u0442\u0438\u043a. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0434\u043e\u043c\u0435\u043d \u043f\u043e\u0434 \u0436\u0438\u0432\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0435\u0439 \u0432\u044b\u0434\u0430\u0451\u0442 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0444\u043e\u0440\u043c\u0430\u0442\u0430 <code>v1.&lt;userId&gt;.&lt;exp&gt;.&lt;hmac&gt;<\/code>, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d 60 \u0441\u0435\u043a\u0443\u043d\u0434. \u041a\u043e\u043d\u0441\u043e\u043b\u044c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0435\u0433\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0430 \u0441\u0432\u043e\u044e host-only \u043a\u0443\u043a\u0443 <code>deploy_session<\/code> \u043d\u0430 30 \u0434\u043d\u0435\u0439. HMAC \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u0435, <code>timingSafeEqual<\/code> \u043f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435. \u0421\u043a\u0443\u0447\u043d\u043e, \u0437\u0430\u0442\u043e \u043d\u0435 \u0440\u0430\u0437\u0432\u0430\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 \u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438 \u0442\u0440\u0435\u0442\u044c\u0438\u0445 \u043a\u0443\u043a.<\/p>\n<p><strong>stdio-\u0441\u0435\u0440\u0432\u0435\u0440\u044b \u0431\u0435\u0437 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.<\/strong> \u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u0445\u043e\u0434 \u0431\u044b\u043b \u00ab\u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u00bb. \u041d\u043e stdio-MCP \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 stdin\/stdout, \u043a \u043d\u0435\u043c\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043f\u043e HTTP. \u0411\u0435\u0437 <code>supergateway<\/code> (\u0438\u043b\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0430) \u0441\u0435\u0442\u0435\u0432\u043e\u0439 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u042d\u0442\u043e \u043d\u0435 \u0433\u0440\u0430\u0431\u043b\u044f \u0434\u0430\u0436\u0435, \u0430 \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u043e\u043d\u0430\u0447\u0430\u043b\u0443 \u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0438\u043b.<\/p>\n<h3>\u0417\u0430\u0447\u0435\u043c \u044d\u0442\u043e \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435, \u0430 \u043d\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c<\/h3>\n<p>\u041c\u043e\u0433\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0434\u0435\u043f\u043b\u043e\u0439 \u0443\u0432\u043e\u0434\u0438\u0442 \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043e\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430. \u041d\u0430 \u0434\u0435\u043b\u0435 \u043e\u043d \u0437\u0430\u043c\u044b\u043a\u0430\u0435\u0442 \u043f\u0435\u0442\u043b\u044e. \u0420\u0430\u043d\u044c\u0448\u0435 Unyly \u043e\u0442\u0432\u0435\u0447\u0430\u043b \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043a\u0430\u043a\u043e\u0439 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0437\u044f\u0442\u044c\u00bb. \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0438 \u043d\u0430 \u00ab\u0433\u0434\u0435 \u0435\u0433\u043e \u0434\u0435\u0440\u0436\u0430\u0442\u044c\u00bb. \u041d\u0430\u0448\u0451\u043b \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439, \u0438 \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0443 \u043c\u0438\u043d\u0443\u0442 \u043e\u043d \u0436\u0438\u0432\u0451\u0442 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c URL, \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044e, \u0431\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0430 \u0438 DevOps-\u043e\u0431\u0432\u044f\u0437\u043a\u0438.<\/p>\n<p>\u041f\u043e\u0449\u0443\u043f\u0430\u0442\u044c: <a href=\"https:\/\/unyly.org\/deploy\" rel=\"noopener noreferrer nofollow\">unyly.org\/deploy<\/a>, \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u043d\u0430 <a href=\"http:\/\/deploy.unyly.org\" rel=\"noopener noreferrer nofollow\">deploy.unyly.org<\/a>. \u041f\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u0438 \u0433\u0440\u0430\u0431\u043b\u044f\u043c \u0433\u043e\u0442\u043e\u0432 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e, \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0432\u044b\u0448\u043b\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c, \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e \u0438 \u0432 \u044d\u0442\u043e\u0442.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1070718\/\">https:\/\/habr.com\/ru\/articles\/1070718\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u043f\u0438\u0441\u0430\u043b \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432: 80 \u0442\u044b\u0441\u044f\u0447 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0434\u0435\u0432\u044f\u0442\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u0435. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0438 \u0432 \u043b\u0438\u0447\u043a\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u0441\u043f\u043b\u044b\u043b \u0432\u043e\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0441\u0430\u043c \u043d\u0435 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043b, \u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433: \u00ab\u043d\u0430\u0448\u0451\u043b \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0435\u0433\u043e \u0433\u0434\u0435?\u00bb\u0421 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0431\u0435\u0434\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u043e\u0431\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0436\u0438\u0432\u0451\u0442 \u043d\u0435 \u043a\u0430\u043a \u0433\u043e\u0442\u043e\u0432\u044b\u0439 npm-\u043f\u0430\u043a\u0435\u0442, \u0430 \u043a\u0430\u043a \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 GitHub. \u0415\u0433\u043e \u043d\u0430\u0434\u043e \u0441\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0441\u043e\u0431\u0440\u0430\u0442\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0436\u0438\u0432\u044b\u043c. \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 stdio (\u0430 \u0442\u0430\u043a\u0438\u0445 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e), \u0441\u0432\u0435\u0440\u0445\u0443 \u0435\u0449\u0451 \u0437\u0430\u0434\u0430\u0447\u0430 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 HTTP, \u0438\u043d\u0430\u0447\u0435 \u043a \u043d\u0435\u043c\u0443 \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u043d\u0438 claude.ai, \u043d\u0438 ChatGPT. \u0418\u0442\u043e\u0433: \u043f\u043e\u0434 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 40 \u0441\u0442\u0440\u043e\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 VPS, \u043f\u0438\u0448\u0435\u0442 Dockerfile, \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 nginx, \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0438 \u0432\u0435\u0448\u0430\u0435\u0442 \u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 \u0430\u0432\u0442\u043e\u0434\u0435\u043f\u043b\u043e\u0439. \u0414\u0438\u0437\u0431\u0430\u043b\u0430\u043d\u0441 \u0443\u0441\u0438\u043b\u0438\u0439 \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u044b\u0439.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0432\u043d\u0443\u0442\u0440\u0438 Unyly \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0434\u0435\u043f\u043b\u043e\u044f. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0448\u044c GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0448\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 slug.unyly.org, \u043f\u0443\u0448 \u0432 \u0432\u0435\u0442\u043a\u0443 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0435\u0433\u043e \u0441\u0430\u043c. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 (\u0441\u0442\u0430\u0442\u0438\u043a\u0430, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u0441\u0431\u043e\u0440\u043a\u0438, Next.js), \u0438 \u0434\u043b\u044f MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 Node \u0438 Python. \u041d\u0438\u0436\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043f\u043e \u0441\u043b\u043e\u044f\u043c \u0438 \u0447\u0435\u0441\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044e \u0433\u0440\u0430\u0431\u043b\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0442\u0435\u0440\u044f\u043b \u0432\u0440\u0435\u043c\u044f. \u041a\u043e\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e.\u0418\u0437 GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u041e\u0431\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430\u041d\u0438\u0447\u0435\u0433\u043e \u044d\u043a\u0437\u043e\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e, \u0432\u0441\u044f \u0441\u0443\u0442\u044c \u0432 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043a\u043b\u0435\u0439\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043a\u0438\u0440\u043f\u0438\u0447\u0435\u0439. \u041f\u043e\u0442\u043e\u043a \u0442\u0430\u043a\u043e\u0439:GitHub push   -&gt; \u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 Next.js API (HMAC-\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430)   -&gt; \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c runner_deploys (SQLite)   -&gt; \u0434\u0435\u043c\u043e\u043d-\u0432\u043e\u0440\u043a\u0435\u0440 \u0431\u0435\u0440\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443        git clone \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u044e\u0437\u0435\u0440\u0430        \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Dockerfile \u043f\u043e\u0434 \u0442\u0438\u043f \u043f\u0440\u043e\u0435\u043a\u0442\u0430        docker build        docker run \u0441 \u043b\u0438\u043c\u0438\u0442\u0430\u043c\u0438        healthcheck   -&gt; \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u043d\u0430 :3900 \u0440\u043e\u0443\u0442\u0438\u0442 \u043f\u043e Host -&gt; \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0412\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c, \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0434\u043e\u0448\u0451\u043b \u043d\u0435 \u0441\u0440\u0430\u0437\u0443: \u043f\u0440\u043e\u043a\u0441\u0438 \u0438 \u0432\u043e\u0440\u043a\u0435\u0440 \u044d\u0442\u043e \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043f\u043e\u0434 pm2 (unyly-runner-proxy \u0438 unyly-runner-worker), \u0430 \u043d\u0435 \u043e\u0434\u0438\u043d. \u041f\u043e\u0447\u0435\u043c\u0443, \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e \u0433\u0440\u0430\u0431\u043b\u0438, \u0442\u0430\u043c \u044d\u0442\u043e \u0441\u0442\u043e\u0438\u043b\u043e \u043c\u043d\u0435 \u043f\u0430\u0440\u044b \u0447\u0430\u0441\u043e\u0432 \u0438 \u0432\u0441\u0435\u0445 \u0436\u0438\u0432\u044b\u0445 \u0441\u0430\u0439\u0442\u043e\u0432.\u0421\u043b\u043e\u0439 1. \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Dockerfile\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c Dockerfile \u043d\u0435 \u043f\u0438\u0448\u0435\u0442. \u0415\u0441\u043b\u0438 \u043e\u043d \u0435\u0441\u0442\u044c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u044f \u0443\u0432\u0430\u0436\u0430\u044e \u0435\u0433\u043e \u0438 \u0431\u0435\u0440\u0443 \u043a\u0430\u043a \u0435\u0441\u0442\u044c. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e \u0441\u0430\u043c \u043f\u043e \u0442\u0438\u043f\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041f\u044f\u0442\u044c \u0440\u0435\u0446\u0435\u043f\u0442\u043e\u0432.MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Node. \u0422\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0438\u0449\u0443 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 bin &gt; main &gt; index.js \u0438\u0437 package.json. \u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: stdio-\u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 supergateway, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 stdin\/stdout \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 streamable HTTP \u043d\u0430 \/mcp. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.FROM node:22-slimWORKDIR \/appCOPY package*.json .\/RUN npm install &#8212;omit=dev &#8212;no-audit &#8212;no-fund || npm install &#8212;no-audit &#8212;no-fundCOPY . .RUN npm install -g supergateway@latest &#8212;no-audit &#8212;no-fundEXPOSE 3000CMD [&#171;sh&#187;, &#171;-c&#187;, &#171;supergateway &#8212;stateful &#8212;stdio &#8216;node index.js&#8217; \\     &#8212;outputTransport streamableHttp &#8212;port 3000 &#8212;streamableHttpPath \/mcp&#187;]MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Python. \u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 python:3.12-slim, \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 requirements.txt \u0438\u043b\u0438 pyproject.toml, \u0430 supergateway (\u043e\u043d \u043d\u0430 Node) \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u0447\u0435\u0440\u0435\u0437 apt-get install nodejs npm. \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 server.py \u0438\u043b\u0438 main.py.\u0421\u0430\u0439\u0442, \u0442\u0440\u0438 \u0440\u0435\u0446\u0435\u043f\u0442\u0430 \u043a\u0430\u043a \u0443 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0435\u043f\u043b\u043e\u0439-\u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0430:\u0427\u0438\u0441\u0442\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u043a\u0430 (\u0435\u0441\u0442\u044c index.html, \u043d\u0435\u0442 package.json) \u0435\u0434\u0435\u0442 \u0432 nginx:alpine.\u0424\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0441\u043e \u0441\u0431\u043e\u0440\u043a\u043e\u0439: \u0433\u043e\u043d\u044f\u044e npm run build \u0438 \u0440\u0430\u0437\u0434\u0430\u044e \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u0448\u043b\u043e\u0441\u044c. \u0422\u0443\u0442 \u0437\u0430\u0431\u0430\u0432\u043d\u044b\u0439 \u043a\u0443\u0441\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0432\u044b\u0445\u043e\u0434\u043d\u0443\u044e \u043f\u0430\u043f\u043a\u0443 \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u043e\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0438\u043c\u0451\u043d:RUN for d in dist build out public .; do \\      if [ -f &#171;$d\/index.html&#187; ]; then cp -r &#171;$d&#187; \/site &amp;&amp; break; fi; \\    done &amp;&amp; test -f \/site\/index.htmlNext.js \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e \u043f\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 next \u0432 package.json \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e next start \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u043e\u043c.\u0414\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 nginx-\u043a\u043e\u043d\u0444\u0438\u0433 \u0441 SPA-\u0444\u043e\u043b\u0431\u044d\u043a\u043e\u043c \u043b\u0435\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 COPY, \u0430 \u043d\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 RUN. \u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a, \u0442\u043e\u0436\u0435 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445, \u0442\u0430\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043f\u0440\u043e $uri.\u0421\u043b\u043e\u0439 2. \u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0421\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441 \u0436\u0451\u0441\u0442\u043a\u0438\u043c\u0438 \u043b\u0438\u043c\u0438\u0442\u0430\u043c\u0438. \u042d\u0442\u043e \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043c\u043e\u0451\u043c \u0436\u0435\u043b\u0435\u0437\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043f\u0440\u0430\u0432.docker run -d &#8212;name &lt;container&gt; &#8212;restart unless-stopped \\  &#8212;memory 384m &#8212;cpus 0.5 &#8212;pids-limit 256 \\  &#8212;cap-drop ALL &#8212;security-opt no-new-privileges \\  -p 127.0.0.1:&lt;port&gt;:3000 \\  &lt;image&gt;\u041f\u043e\u0440\u0442 \u0441\u043b\u0443\u0448\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 localhost, \u043d\u0430\u0440\u0443\u0436\u0443 \u0435\u0433\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438. &#8212;cap-drop ALL \u0443\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0435 \u043b\u0438\u043d\u0443\u043a\u0441\u043e\u0432\u044b\u0435 capabilities. \u041e\u0434\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: nginx \u0432 site-\u043e\u0431\u0440\u0430\u0437\u0430\u0445 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u0431\u0435\u0437 CHOWN, SETUID, SETGID (\u0435\u043c\u0443 \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440\u044b \u043d\u0430 unprivileged-\u044e\u0437\u0435\u0440\u0430), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0438\u043c \u0442\u0440\u0451\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c \u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0445. MCP-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0436\u0438\u0432\u0443\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437 capabilities.\u0421\u043b\u043e\u0439 3. Healthcheck, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0412\u043e\u0442 \u0442\u0443\u0442 \u044f \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u0445\u043e\u0442\u0435\u043b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u00ab\u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0434\u043d\u044f\u043b\u0441\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 \u0436\u0438\u0432\u043e\u0439\u00bb. \u0414\u043b\u044f \u0441\u0430\u0439\u0442\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: HTTP-\u043a\u043e\u0434 2xx \u0438\u043b\u0438 3xx \u043d\u0430 \/. \u0410 \u0432\u043e\u0442 \u0434\u043b\u044f MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 healthcheck \u044d\u0442\u043e \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 JSON-RPC initialize \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 MCP, \u0441 \u0434\u0435\u0434\u043b\u0430\u0439\u043d\u043e\u043c 60 \u0441\u0435\u043a\u0443\u043d\u0434:curl -s &#8212;max-time 5 -X POST http:\/\/127.0.0.1:&lt;port&gt;\/mcp \\  -H &#8216;content-type: application\/json&#8217; \\  -H &#8216;accept: application\/json, text\/event-stream&#8217; \\  -d &#8216;{&#171;jsonrpc&#187;:&#187;2.0&#8243;,&#187;id&#187;:1,&#187;method&#187;:&#187;initialize&#187;,       &#171;params&#187;:{&#171;protocolVersion&#187;:&#187;2025-03-26&#8243;,&#187;capabilities&#187;:{},       &#171;clientInfo&#187;:{&#171;name&#187;:&#187;unyly-health&#187;,&#187;version&#187;:&#187;1.0&#8243;}}}&#8217;\u0415\u0441\u043b\u0438 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0435\u0441\u0442\u044c &#171;result&#187;, \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043d\u0430 MCP, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u043b \u043f\u043e\u0440\u0442. \u041d\u0435 \u043f\u0440\u043e\u0448\u0451\u043b \u0437\u0430 \u043c\u0438\u043d\u0443\u0442\u0443: \u0442\u044f\u043d\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 40 \u0441\u0442\u0440\u043e\u043a docker logs \u043f\u0440\u044f\u043c\u043e \u0432 \u043b\u043e\u0433 \u0434\u0435\u043f\u043b\u043e\u044f, \u0447\u0442\u043e\u0431\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0432 \u043a\u0430\u0431\u0438\u043d\u0435\u0442\u0435 \u0432\u0438\u0434\u0435\u043b \u043f\u0440\u0438\u0447\u0438\u043d\u0443, \u0430 \u043d\u0435 \u00abfailed\u00bb.\u0421\u043b\u043e\u0439 4. \u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u043f\u043e Host \u0438 nginx-\u0440\u0435\u0433\u044d\u043a\u0441\u043f\u0420\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u043d\u0430 :3900 \u0441\u043c\u043e\u0442\u0440\u0438\u0442 \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a Host \u0438 \u043f\u043e \u043d\u0435\u043c\u0443 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440: slug.unyly.org, \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d \u0438\u043b\u0438 \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430. nginx \u043e\u0442\u0434\u0430\u0451\u0442 \u0432\u0435\u0441\u044c wildcard-\u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d \u0432 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u043a\u0441\u0438. \u0418 \u0432\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u0430 \u043c\u0438\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u043f\u043e\u0434\u043e\u0440\u0432\u0430\u043b\u0441\u044f (\u0434\u0435\u0442\u0430\u043b\u0438 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445). \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 server_name \u044d\u0442\u043e \u0440\u0435\u0433\u044d\u043a\u0441\u043f \u0441 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u043e\u043c \u0432\u043f\u0435\u0440\u0451\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u044b:server_name ~^(?!(www|app|api|admin|gateway|staging|run|mail|smtp|ftp|deploy)\\.)[a-z0-9-]+\\.unyly\\.org$;\u0422\u043e \u0435\u0441\u0442\u044c \u00ab\u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d, \u043a\u0440\u043e\u043c\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445\u00bb. \u041f\u0440\u043e\u0441\u0442\u043e\u0439 *.unyly.org \u0442\u0443\u0442 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438.\u0421\u043b\u043e\u0439 5. \u0410\u0432\u0442\u043e\u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u043e\u0432\u041f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u044f \u0432\u0435\u0448\u0430\u044e GitHub-\u0432\u0435\u0431\u0445\u0443\u043a \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f push \u0438 pull_request. \u041f\u043e\u0434\u043f\u0438\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e \u0447\u0435\u0441\u0442\u043d\u043e, X-Hub-Signature-256, HMAC-SHA256 \u043e\u0442 \u0441\u044b\u0440\u043e\u0433\u043e \u0442\u0435\u043b\u0430:const expected = &#8216;sha256=&#8217; + createHmac(&#8216;sha256&#8217;, project.webhook_secret).update(raw).digest(&#8216;hex&#8217;)\/\/ \u0434\u0430\u043b\u0435\u0435 timingSafeEqual, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0435\u0447\u044c \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044fPush \u0432 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043a\u043b\u0430\u0434\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0434\u0435\u043f\u043b\u043e\u0435\u0432 \u0438 \u043b\u043e\u0433\u0438 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u0430\u0431\u0438\u043d\u0435\u0442\u0435. \u0421 \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435: \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 PR \u044f \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u044e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442-\u043f\u0440\u0435\u0432\u044c\u044e \u0441\u043e \u0441\u0432\u043e\u0438\u043c \u0441\u043b\u0430\u0433\u043e\u043c (parent_id \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u043f\u043b\u044e\u0441 pr_number), \u0431\u0438\u043b\u0436\u0443 \u0432\u0435\u0442\u043a\u0443 PR \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442. \u0417\u0430\u043a\u0440\u044b\u043b\u0438 PR, \u043f\u0440\u0435\u0432\u044c\u044e \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u043e. \u0424\u043e\u0440\u043a-\u043f\u0443\u043b\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u044b \u043d\u0435 \u0431\u0438\u043b\u0436\u0443, \u0442\u0430\u043c \u0447\u0443\u0436\u043e\u0439 \u043a\u043e\u0434 \u0441 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0441\u0435\u043a\u0440\u0435\u0442\u0430\u043c, \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e.\u0427\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435\u041a\u043e\u043d\u0441\u043e\u043b\u044c \u0438 \u0442\u0438\u043f\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u043e \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d deploy.unyly.org: \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0434\u0435\u043f\u043b\u043e\u0438 \u0441 \u043b\u043e\u0433\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438, runtime-\u043b\u043e\u0433\u0438, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 CPU \u0438 RAM, \u0433\u0440\u0430\u0444\u0438\u043a \u0442\u0440\u0430\u0444\u0438\u043a\u0430, \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0434\u043e\u043c\u0435\u043d\u044b, \u043e\u0442\u043a\u0430\u0442\u044b. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0431\u044b\u043b\u0430 \u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u044d\u0442\u043e\u0439 \u043a\u043e\u043d\u0441\u043e\u043b\u0438, \u043e \u043d\u0435\u0439 \u043d\u0438\u0436\u0435 \u0432 \u0433\u0440\u0430\u0431\u043b\u044f\u0445.\u0422\u0430\u0440\u0438\u0444\u043d\u043e \u0434\u0435\u043f\u043b\u043e\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u0432 \u043e\u0431\u0449\u0443\u044e \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 Unyly, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043e\u0440\u043e\u0431\u043a\u043e\u0439: \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u0430 Pro \u0434\u0435\u0441\u044f\u0442\u044c \u043f\u043b\u044e\u0441 \u043f\u0440\u0435\u0432\u044c\u044e PR \u0438 \u0441\u0432\u043e\u0438 \u0434\u043e\u043c\u0435\u043d\u044b.Deploy \u0432 \u0442\u0430\u0440\u0438\u0444\u0430\u0445\u0416\u0438\u0432\u043e\u0439 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u043d\u0430 hello.unyly.org: \u043e\u0434\u0438\u043d index.html, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u043f\u0443\u0448 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442.\u0421\u0430\u0439\u0442, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u044f \u0437\u0430\u0434\u043e\u043b\u0431\u0430\u043b\u0441\u044f, \u043d\u043e \u0441\u0434\u0435\u043b\u0430\u043b \u0432\u0441\u0435 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0440\u0435\u043d\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f, \u0441\u0442\u043e\u0438\u0442 \u043d\u0430 \u043f\u0430\u0443\u0437\u0435, \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0441\u043d\u0430 \u0438\u043b\u0438 \u0441\u043b\u0430\u0433\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442: \u0432\u0435\u0437\u0434\u0435 \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u044b\u0439 \u0435\u0434\u0438\u043d\u043e\u0440\u043e\u0433 \u0438 \u0432\u043d\u044f\u0442\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0432\u043c\u0435\u0441\u0442\u043e \u0433\u043e\u043b\u043e\u0433\u043e nginx-\u043d\u043e\u0433\u043e 404 Not Found. \u0414\u0430\u0436\u0435 \u0444\u0430\u0432\u0438\u043a\u043e\u043d\u043a\u0443, \u0435\u0441\u043b\u0438 \u0443 \u0441\u0430\u0439\u0442\u0430 \u0441\u0432\u043e\u0435\u0439 \u043d\u0435\u0442, \u043e\u0442\u0434\u0430\u044e \u0435\u0434\u0438\u043d\u043e\u0440\u043e\u0433\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0441\u0438\u0440\u043e\u0442\u043e\u0439.\u0411\u0440\u0435\u043d\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0443\u0441-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0413\u0440\u0430\u0431\u043b\u0438, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u044b\u0447\u043d\u043e \u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0411\u0438\u043b\u0434 \u0433\u043b\u0443\u0448\u0438\u043b \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u0441\u0435 \u0441\u0430\u0439\u0442\u044b. \u041f\u0440\u043e\u043a\u0441\u0438 \u0438 \u0432\u043e\u0440\u043a\u0435\u0440 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0436\u0438\u043b\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c node-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435. \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 docker build \u0447\u0435\u0440\u0435\u0437 execFileSync \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b event loop \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u041f\u043e\u043a\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0435\u043a\u0442 (\u0430 \u044d\u0442\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0441\u0435\u043a\u0443\u043d\u0434), \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442, \u0438 \u0432\u0441\u0435 \u0440\u0430\u043d\u043d\u0435\u0440-\u0441\u0430\u0439\u0442\u044b \u0440\u0430\u0437\u043e\u043c \u043e\u0442\u0434\u0430\u044e\u0442 502. \u0420\u0430\u0437\u0432\u0451\u043b \u043d\u0430 \u0434\u0432\u0430 pm2-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u0440\u043e\u043b\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c. \u0417\u0430\u0434\u043d\u0438\u043c \u0447\u0438\u0441\u043b\u043e\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0435 \u043d\u0435\u0442.printf \u0432 Dockerfile \u043b\u043e\u043c\u0430\u043b nginx. SPA-\u0444\u043e\u043b\u0431\u044d\u043a \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b \u043f\u0440\u044f\u043c\u043e \u0432 RUN \u0447\u0435\u0440\u0435\u0437 printf. \u0412\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 try_files $uri $uri\/ \/index.html, \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e $uri \u0441\u044a\u0435\u0434\u0430\u043b \u0448\u0435\u043b\u043b \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u043a\u0438. \u041f\u043e\u043b\u0443\u0447\u0430\u043b\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433 \u0431\u0435\u0437 $uri, nginx \u0443\u0445\u043e\u0434\u0438\u043b \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442-\u0446\u0438\u043a\u043b, \u043e\u0442\u0434\u0430\u0432\u0430\u043b 500. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043a\u043e\u043d\u0444\u0438\u0433 \u043b\u0435\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 COPY, \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.Wildcard-\u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0430\u0434\u043c\u0438\u043d\u043a\u0443. \u0421\u0430\u043c\u0430\u044f \u044d\u043f\u0438\u0447\u043d\u0430\u044f. \u041f\u043e\u0432\u0435\u0441\u0438\u043b \u043d\u0430 \u043f\u0440\u043e\u043a\u0441\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432 *.unyly.org \u0438 \u043e\u043d \u0440\u0430\u0434\u043e\u0441\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u043b admin.unyly.org \u0438 gateway.unyly.org, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0434\u0440\u0443\u0433\u043e\u043c server-\u0431\u043b\u043e\u043a\u0435. \u0410\u0434\u043c\u0438\u043d\u043a\u0430 \u043b\u0435\u0433\u043b\u0430 \u0441 \u00abnot found\u00bb, \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043e\u0442 \u043a\u043e\u043b\u043b\u0435\u0433\u0438 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e \u00ab\u0431\u0440\u043e \u0432\u0442\u0444\u00bb. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0433\u044d\u043a\u0441\u043f \u0441 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u043e\u043c \u0432\u043f\u0435\u0440\u0451\u0434 (\u0441\u043c. \u0441\u043b\u043e\u0439 4), \u0438 default_server \u043d\u0430 \u044d\u0442\u043e\u043c \u0431\u043b\u043e\u043a\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u0436\u0435 \u043d\u0435\u043b\u044c\u0437\u044f, \u0438\u043d\u0430\u0447\u0435 \u043e\u043d \u043d\u0430\u0447\u043d\u0451\u0442 \u043b\u043e\u0432\u0438\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0435.\u041a\u0443\u043a\u0438 \u043d\u0435 \u0445\u043e\u0434\u044f\u0442 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438. \u041a\u043e\u043d\u0441\u043e\u043b\u044c \u043d\u0430 deploy.unyly.org, \u0430 \u0441\u0435\u0441\u0441\u0438\u044f \u0443 \u043c\u0435\u043d\u044f host-only \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043e\u043c\u0435\u043d\u0435. Cross-subdomain \u043a\u0443\u043a\u0438 \u044f \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u044e: Brave \u0438 Safari \u0441 \u0438\u0445 \u0442\u0440\u0435\u043a\u0438\u043d\u0433-\u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u0440\u043e\u043d\u044f\u044e\u0442 \u043d\u0430 \u043d\u0438\u0445 OAuth. \u041f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c SSO-\u043c\u043e\u0441\u0442\u0438\u043a. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0434\u043e\u043c\u0435\u043d \u043f\u043e\u0434 \u0436\u0438\u0432\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0435\u0439 \u0432\u044b\u0434\u0430\u0451\u0442 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0444\u043e\u0440\u043c\u0430\u0442\u0430 v1.&lt;userId&gt;.&lt;exp&gt;.&lt;hmac&gt;, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d 60 \u0441\u0435\u043a\u0443\u043d\u0434. \u041a\u043e\u043d\u0441\u043e\u043b\u044c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0435\u0433\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0430 \u0441\u0432\u043e\u044e host-only \u043a\u0443\u043a\u0443 deploy_session \u043d\u0430 30 \u0434\u043d\u0435\u0439. HMAC \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u0435, timingSafeEqual \u043f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435. \u0421\u043a\u0443\u0447\u043d\u043e, \u0437\u0430\u0442\u043e \u043d\u0435 \u0440\u0430\u0437\u0432\u0430\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 \u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438 \u0442\u0440\u0435\u0442\u044c\u0438\u0445 \u043a\u0443\u043a.stdio-\u0441\u0435\u0440\u0432\u0435\u0440\u044b \u0431\u0435\u0437 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b \u0432 \u0441\u0435\u0442\u0438. \u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u0445\u043e\u0434 \u0431\u044b\u043b \u00ab\u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u00bb. \u041d\u043e stdio-MCP \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 stdin\/stdout, \u043a \u043d\u0435\u043c\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043f\u043e HTTP. \u0411\u0435\u0437 supergateway (\u0438\u043b\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0430) \u0441\u0435\u0442\u0435\u0432\u043e\u0439 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u042d\u0442\u043e \u043d\u0435 \u0433\u0440\u0430\u0431\u043b\u044f \u0434\u0430\u0436\u0435, \u0430 \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u043e\u043d\u0430\u0447\u0430\u043b\u0443 \u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0438\u043b.\u0417\u0430\u0447\u0435\u043c \u044d\u0442\u043e \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435, \u0430 \u043d\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c\u041c\u043e\u0433\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0434\u0435\u043f\u043b\u043e\u0439 \u0443\u0432\u043e\u0434\u0438\u0442 \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043e\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430. \u041d\u0430 \u0434\u0435\u043b\u0435 \u043e\u043d \u0437\u0430\u043c\u044b\u043a\u0430\u0435\u0442 \u043f\u0435\u0442\u043b\u044e. \u0420\u0430\u043d\u044c\u0448\u0435 Unyly \u043e\u0442\u0432\u0435\u0447\u0430\u043b \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043a\u0430\u043a\u043e\u0439 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0437\u044f\u0442\u044c\u00bb. \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0438 \u043d\u0430 \u00ab\u0433\u0434\u0435 \u0435\u0433\u043e \u0434\u0435\u0440\u0436\u0430\u0442\u044c\u00bb. \u041d\u0430\u0448\u0451\u043b \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439,&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-491009","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/491009","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=491009"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/491009\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=491009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=491009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=491009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}