{"id":346172,"date":"2023-03-02T15:05:17","date_gmt":"2023-03-02T15:05:17","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=346172"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2023-03-02T15:05:17","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=346172","title":{"rendered":"<span>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Typescript \u0441 Nest, Nuxt 3 \u0438 Docker<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0420\u0435\u0448\u0438\u043b \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u00a0Typescript \u0441\u00a0Nest \u043d\u0430\u00a0\u0431\u0435\u043a\u0435\u043d\u0434\u0435, Nuxt (SPA) \u043d\u0430\u00a0\u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435. \u0412\u0441\u0435 \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u043e\u0434\u0438\u043d docker\u2011\u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a\u00a0standalone \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 c nginx, healthcheck\u00bb\u0430\u043c\u0438, \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0448\u2026\u0448\u0438\u0440\u043e\u043a\u043e\u0439 \u0441\u0444\u0435\u0440\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/8d3\/e66\/88a\/8d3e6688a6dfb96db7ff054a3a1cea45.jpg\" width=\"961\" height=\"540\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8d3\/e66\/88a\/8d3e6688a6dfb96db7ff054a3a1cea45.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0435\u043b\u0430\u043b \u044d\u0442\u043e \u0432\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f\u00a0\u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438\u043b\u0438\u00a0\u0441\u00a0\u0446\u0435\u043b\u044c\u044e \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f Nest, Nuxt 3\u00a0\u0441\u00a0composable \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043a\u0430\u043a\u00a0\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043a\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0437\u0430\u00a0\u043e\u0441\u043d\u043e\u0432\u0443 \u043a\u043e\u0434 \u0441 <a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\" rel=\"noopener noreferrer nofollow\">github<\/a>.<\/p>\n<h3>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0428\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u00a0\u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u0433\u043e docker\u2011\u043e\u0431\u0440\u0430\u0437\u0430, \u0432\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <code>nest<\/code>+<code>nginx<\/code> \u0438 \u0441\u043e\u0431\u0440\u0430\u043d\u044b <code>backend<\/code> \u0438 <code>frontend<\/code>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d83\/783\/bf9\/d83783bf964a69bb0a279dec153b2882.gif\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" width=\"853\" height=\"480\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d83\/783\/bf9\/d83783bf964a69bb0a279dec153b2882.gif\"\/><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/figcaption><\/figure>\n<h4>\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0443 \u0438\u0437 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<pre><code>\u2514\u2500\u2500 application\/     \u251c\u2500\u2500 backend\/     \u2502   \u2514\u2500\u2500 NEST \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     \u251c\u2500\u2500 frontend\/     \u2502   \u2514\u2500\u2500 NUXT \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     \u251c\u2500\u2500 docker\/     \u2502   \u2514\u2500\u2500 nginx\/     \u2502       \u2514\u2500\u2500 conf.conf     \u251c\u2500\u2500 .dockerignore     \u251c\u2500\u2500 .gitignore     \u251c\u2500\u2500 docker-compose.yml     \u251c\u2500\u2500 Dockerfile     \u2514\u2500\u2500 readme.md<\/code><\/pre>\n<ul>\n<li>\n<p><code>backend<\/code> \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c <a href=\"https:\/\/github.com\/nestjs\/serve-static\" rel=\"noopener noreferrer nofollow\">serve-static<\/a> \u043c\u043e\u0434\u0443\u043b\u0435\u043c;<\/p>\n<\/li>\n<li>\n<p><code>frontend<\/code> \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 nuxt \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u044c\u044e \u0441 <code>backend<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>docker<\/code> \u2014 \u043f\u0430\u043f\u043a\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0439\u0434\u0443\u0442 \u0432 docker \u043e\u0431\u0440\u0430\u0437 (\u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u043e\u043b\u044c\u043a\u043e nginx);<\/p>\n<\/li>\n<li>\n<p><code>Dockerfile<\/code> \u2014 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043f\u043e \u0441\u0431\u043e\u0440\u043a\u0435 \u0434\u043e\u043a\u0435\u0440-\u043e\u0431\u0440\u0430\u0437\u0430;<\/p>\n<\/li>\n<li>\n<p><code>docker-compose.yml<\/code> \u2014 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\" rel=\"noopener noreferrer nofollow\">github<\/a>, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>docker-compose up -d<\/code> (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e\u00a0\u0437\u0430\u043f\u0443\u0441\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0432\u00a0\u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438) \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u00a0\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0438\u0436\u0435 \u044f \u043e\u043f\u0438\u0441\u0430\u043b \u0447\u0442\u043e\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043e \u0432\u00a0\u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0438 \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438<\/p>\n<blockquote>\n<p>\u0412\u00a0\u044d\u0442\u043e\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u043d\u0435\u0442 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043a\u0430\u043a\u0438\u0445\u2011\u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/blockquote>\n<h4>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/h4>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Nginx. \u041e\u043d \u0440\u0430\u0437\u0434\u0430\u0435\u0442 \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0431\u0435\u043a\u0435\u043d\u0434, \u0435\u0441\u043b\u0438 URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>\/api<\/code><\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 2 \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/898\/5fc\/4ab\/8985fc4abefa4722ca22b8e0a67a1779.png\" width=\"942\" height=\"482\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/898\/5fc\/4ab\/8985fc4abefa4722ca22b8e0a67a1779.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0418 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e3e\/5ee\/4fc\/e3e5ee4fcc7dcf00dd9aa5f5e022d902.png\" width=\"930\" height=\"694\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e3e\/5ee\/4fc\/e3e5ee4fcc7dcf00dd9aa5f5e022d902.png\"\/><figcaption><\/figcaption><\/figure>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Backend \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0437\u044f\u0442 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 <a href=\"https:\/\/docs.nestjs.com\/\" rel=\"noopener noreferrer nofollow\">nest<\/a>:<\/p>\n<pre><code class=\"bash\">$ npm i -g @nestjs\/cli $ nest new backend<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0432 <code>main.ts<\/code> \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0440\u0442 \u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0430 3001, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>\/api<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c <code>main.ts<\/code> \u043e\u0431\u0440\u0435\u0442\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"typescript\">import { NestFactory } from '@nestjs\/core'; import { AppModule } from '.\/app.module';  async function bootstrap() {   const app = await NestFactory.create(AppModule);   const port = process.env.APP_PORT || 3001;   app.setGlobalPrefix('api');   app.enableCors();   await app.listen(port); } bootstrap();<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 static \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438<\/h4>\n<p>\u0412\u00a0\u043f\u0430\u043f\u043a\u0443 static \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 html\/js\/css \u0431\u0430\u043d\u0434\u043b \u0441\u00a0nuxt \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a\u00a0\u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0435\u0437\u00a0nginx.<\/p>\n<blockquote>\n<p>\u0414\u0430, \u043f\u0440\u0438\u00a0\u043f\u0440\u043e\u0447\u0438\u0445 \u0440\u0430\u0432\u043d\u044b\u0445, \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u00a0nginx \u0438 \u0434\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u043d\u0435\u00a0\u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0432\u00a0\u043f\u0430\u043f\u043a\u0443 static \u043d\u0438\u0447\u0435\u0433\u043e.<\/p>\n<p>\u041d\u043e\u00a0\u043d\u0430 \u0442\u043e \u044d\u0442\u043e \u0438 \u0431\u043e\u0439\u043b\u0435\u0440, \u0447\u0442\u043e\u00a0\u044f \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435\u00a0\u0437\u043d\u0430\u044e \u043a\u0430\u043a\u00a0\u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438 \u0433\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f. \u041c\u043e\u0436\u0435\u0442\u00a0\u0431\u044b\u0442\u044c, \u0432\u00a0\u043a\u0430\u043a\u0438\u0445 \u0442\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u043f\u0440\u0438\u00a0\u043c\u0430\u043b\u044b\u0445 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u0445, \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0438\u0441\u0442\u043e\u0433\u043e Nest.<\/p>\n<\/blockquote>\n<p>\u0414\u043b\u044f\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b nest \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u043b \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/nestjs\/serve-static\" rel=\"noopener noreferrer nofollow\">serve\u2011static<\/a> \u0432\u043d\u0443\u0442\u0440\u044c <code>AppModule<\/code><\/p>\n<pre><code class=\"typescript\">import { Module } from '@nestjs\/common'; import { AppController } from '.\/app.controller'; import { AppService } from '.\/app.service'; import { ServeStaticModule } from '@nestjs\/serve-static'; import * as path from 'path';  @Module({   imports: [     ServeStaticModule.forRoot({       rootPath: path.join(__dirname, '..', 'static'),       serveRoot: '\/',       exclude: ['\/api*'],     }),   ],   controllers: [AppController],   providers: [AppService], }) export class AppModule {}<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0\u0431\u043b\u043e\u043a <code>exclude: ['\/api*']<\/code>. \u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0442\u0430\u0442\u0438\u043a\u0430 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u043d\u0430\u00a0\u0432\u0441\u0435\u0445 \u0441\u0441\u044b\u043b\u043a\u0430\u0445, \u043a\u0440\u043e\u043c\u0435 <code>\/api<\/code>\u00a0\u2014 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u00a0\u043f\u0443\u0442\u0438 <code>\/api<\/code> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0441\u0430\u043c\u043e nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0412\u00a0\u0441\u0430\u043c\u0443 \u043f\u0430\u043f\u043a\u0443 static \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c <code>.gitignore<\/code> \u0441\u00a0\u0434\u0432\u0443\u043c\u044f \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c\u0438:<\/p>\n<pre><code>* !index.html<\/code><\/pre>\n<p>\u0418 index.html, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0432 \u044d\u0442\u0443 \u043f\u0430\u043f\u043a\u0443 \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f html\/js\/css \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<h4>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430 \u043a api<\/h4>\n<p>\u0412 nest \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>\/api<\/code> \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 \u043f\u0440\u0438\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c <code>\/api<\/code> \u0432 <code>@Controller('\/api\/controller-route')<\/code><\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441<\/p>\n<\/li>\n<\/ul>\n<p>\u042f \u0432 \u0441\u0432\u043e\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0432\u0442\u043e\u0440\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u0414\u043b\u044f \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 <code>main.ts<\/code> \u0441\u0442\u0440\u043e\u0447\u043a\u0443 <code>app.setGlobalPrefix('api');<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c e2e \u0442\u0435\u0441\u0442, \u0447\u0442\u043e\u0431\u044b \u0432 \u043d\u0435\u043c \u0442\u043e\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 e2e \u0442\u0435\u0441\u0442\u044b \u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e, \u044f \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u043d\u043e\u0448\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">export async function createTestingApp() { return (   await Test.createTestingModule({     imports: [AppModule],   }).compile() )   .createNestApplication()   .setGlobalPrefix('api'); }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u044f \u0443\u0436\u0435, \u0432 \u0442\u0435\u0441\u0442\u0430\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u043c\u0435\u0441\u0442\u043e \u0448\u0442\u0430\u0442\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">import { createTestingApp } from '.\/utils\/create-testing-app';  \/\/ .....  beforeEach(async () => {   app = await createTestingApp();   await app.init(); });<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u042f \u0443\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0432\u00a0\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0431\u043b\u043e\u043a\u0435, \u043d\u043e\u00a0\u043f\u043e\u00a0\u0442\u0435\u0441\u0442\u0430\u043c \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0435\u0449\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<ul>\n<li>\n<p>\u0443\u0434\u0430\u043b\u0438\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 spec \u0444\u0430\u0439\u043b \u0443\u00a0\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u0442.\u043a. \u0441\u0430\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e e2e \u0442\u0435\u0441\u0442\u044b \u0438 \u0443\u0437\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0448\u0443 \u0432\u00a0\u0440\u0435\u0434\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043c\u0435\u043d\u044f\u043b \u0444\u043e\u0440\u043c\u0430\u0442 <code>jest.e2e.config.json<\/code> \u043d\u0430 <code>js<\/code>, \u0442\u043a, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e, \u0432\u00a0\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 IDE js \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043b \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0442\u0435\u0441\u0442 \u0441\u00a0\u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c <code>\/api<\/code> \u0432\u00a0\u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Frontend<\/h3>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f Nuxt 3 \u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443<\/p>\n<pre><code class=\"bash\">yarn create nuxt-app frontend<\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u044f \u043d\u0435\u00a0\u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Nuxt \u0441\u00a0SSR, \u0442.\u043a. \u0443\u00a0\u043c\u0435\u043d\u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0447\u0438\u0441\u0442\u043e SPA \u043f\u043e\u0434\u0445\u043e\u0434 (\u043a\u043e\u0433\u0434\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u043a\u00a0\u0441\u0435\u0431\u0435 \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0443\u0436\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441).<\/p>\n<p>\u0414\u0430, SSR \u043a\u043b\u0430\u0441\u0441\u043d\u043e \u0438 \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043d\u043e\u00a0\u0441\u0447\u0438\u0442\u0430\u044e \u0435\u0433\u043e \u0443\u043c\u0435\u0441\u0442\u043d\u044b\u043c \u0432\u00a0\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0441\u00a0\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c SEO \u0438\u043b\u0438\u00a0\u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0447\u0430\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043a\u0440\u044b\u0442\u044c \u043e\u0442\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0435\u2011\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f).<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ba0\/3ae\/379\/ba03ae3799c53203984f05802f881dfa.gif\" width=\"853\" height=\"480\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ba0\/3ae\/379\/ba03ae3799c53203984f05802f881dfa.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u00a0\u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u0440\u0438\u00a0\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u00ab\u043f\u0435\u0440\u0435\u043e\u0431\u0443\u0442\u044c\u00bb \u043d\u0430\u00a0\u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u00a0SSR. \u0427\u0442\u043e\u00a0\u0431\u044b \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c SSR \u0440\u0435\u0436\u0438\u043c \u043d\u0430\u0434\u043e \u0432 <code>nuxt.config.ts<\/code> \u0443\u043a\u0430\u0437\u0430\u0442\u044c <code>ssr: false<\/code><\/p>\n<h4>\u041f\u0430\u0440\u0430 \u0441\u043b\u043e\u0432 \u043f\u0440\u043e Options \u0438 Composition<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0434\u0430\u0432\u043d\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441\u00a0Vue, \u0442\u043e \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e\u00a0\u0440\u0430\u043d\u044c\u0448\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043c\u043e\u0436\u043d\u043e\u00a0\u0431\u044b\u043b\u043e \u0434\u0435\u043b\u0430\u0442\u044c vue \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 Options \u043f\u043e\u0434\u0445\u043e\u0434 (\u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u00a0\u043f\u043e\u043b\u044f\u043c\u0438 data, computed \u0438 \u0442\u0434). \u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437 setup \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u043c\u043d\u0435 \u0434\u043e\u00a0\u043a\u043e\u043d\u0446\u0430 \u043d\u0435\u00a0\u044f\u0441\u043d\u044b \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<p>\u042f\u00a0\u0436\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f, \u043f\u043e\u043a\u0430 \u0447\u0442\u043e, \u043d\u0430\u00a0\u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0447\u0435\u0440\u0435\u0437 options \u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u044f\u044e compose \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u00a0\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445. \u0412\u00a0\u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043d\u0430\u0431\u043e\u0440\u0435 \u044f \u0432\u044b\u0431\u0440\u0430\u043b Composition \u043f\u043e\u0434\u0445\u043e\u0434, \u0442.\u043a. \u0442\u0443\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0442 \u0438 \u0437\u0430\u043e\u0434\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c.<\/p>\n<h4>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 NuxtPage<\/h4>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0432 <code>App.vue<\/code> \u043d\u0435\u00a0\u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d <code>NuxtPage<\/code> \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0439\u043b\u044b \u0432 <code>pages<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435\u00a0\u0431\u0443\u0434\u0435\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <code>App.Vue<\/code> \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0432\u0438\u0434\u0443:<\/p>\n<pre><code class=\"xml\">&lt;template>   &lt;div>     &lt;NuxtPage \/>   &lt;\/div> &lt;\/template><\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u00a0\u043f\u0430\u043f\u043a\u0435 <code>pages\/<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u00a0\u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u0432\u00a0\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/nuxt.com\/docs\/guide\/directory-structure\/pages\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h4>\u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043a API<\/h4>\n<p>\u0414\u043b\u044f\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441\u2011\u043b\u043e\u0433\u0438\u043a\u0438 \u0432\u043e\u00a0Vue 3\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/vuejs.org\/guide\/reusability\/composables.html\" rel=\"noopener noreferrer nofollow\">Composable<\/a> \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0420\u0430\u043d\u044c\u0448\u0435 \u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u043b \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0432\u0435\u0449\u0438 \u0432\u00a0\u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u0441\u00a0\u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439 \u0445\u0435\u0434\u0435\u0440\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 + \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f baseUrl \u0438\u0437\u00a0env \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439.<\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u044f \u0441\u0434\u0435\u043b\u0430\u044e \u043f\u043e\u2011\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0439 composable \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0449\u0435\u0439 <code>useFetch<\/code>. \u0412\u00a0Nuxt composables \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f <a href=\"https:\/\/nuxt.com\/docs\/guide\/directory-structure\/composables\" rel=\"noopener noreferrer nofollow\">\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438<\/a>, \u0441\u043e\u0437\u0434\u0430\u0432 \u0444\u0430\u0439\u043b \u0432\u00a0\u043f\u0430\u043f\u043a\u0435 <code>composables<\/code>.<\/p>\n<pre><code class=\"typescript\">\/\/ frontend\/composables\/api.ts import { UseFetchOptions } from '#app'; import { NitroFetchRequest } from 'nitropack'; import { KeyOfRes } from 'nuxt\/dist\/app\/composables\/asyncData';  export function useApiRequest&lt;T>(   request: NitroFetchRequest,   opts?:     | UseFetchOptions&lt;T extends void ? unknown : T,     (res: T extends void ? unknown : T) => T extends void ? unknown : T,     KeyOfRes&lt;(res: T extends void ? unknown : T) => T extends void ? unknown : T>>     | undefined ) {   const config = useRuntimeConfig();    return useFetch(request, {baseURL: config.public.baseURL, ...opts}); }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f <code>config.public.baseURL<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c <code>nuxt.config.ts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"typescript\">export default defineNuxtConfig({   ssr: false,   runtimeConfig: {     public: {       baseURL: process.env.API_URL || 'http:\/\/localhost:3001\/',     },   }, }) <\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c, \u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, <code>baseURL<\/code> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u0435\u043d <code>http:\/\/localhost:3001\/<\/code>, \u0447\u0442\u043e\u0431\u044b, \u043f\u0440\u0438\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 Nest. \u041f\u0440\u0438\u00a0\u0441\u0431\u043e\u0440\u043a\u0435 \u0431\u0443\u0434\u0443 \u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 <code>\/api<\/code>.<\/p>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f API \u0432\u044b\u0437\u043e\u0432\u0430<\/h4>\n<p>\u0412\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0432\u00a0\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 \u0432 <code>\/api\/test<\/code> \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u00a0\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 \u0432\u0441\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code class=\"typescript\">&lt;template>   &lt;div>     &lt;template v-if=\"pending\">       Loading     &lt;\/template>     &lt;template v-else>       &lt;template v-if=\"data\">         Api result: {{ data }}       &lt;\/template>       &lt;template v-else-if=\"error\">         Api ERROR: {{ error }}       &lt;\/template>       &lt;button @click=\"refresh()\">refresh&lt;\/button>     &lt;\/template>   &lt;\/div> &lt;\/template>  &lt;script setup> import { useApiRequest } from '..\/composables\/api'  const { data, pending, error, refresh } = useApiRequest('\/api\/test') &lt;\/script><\/code><\/pre>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0438 docker-compose.yml<\/h3>\n<p>\u0412 \u0441\u0432\u043e\u0435\u043c \u043b\u0438\u0447\u043d\u043e\u043c \u0431\u043b\u043e\u0433\u0435 \u044f <a href=\"https:\/\/yandex.ru\/clck\/jsredir?from=yandex.ru%3Bsearch%2F%3Bweb%3B%3B&amp;text=&amp;etext=2202._IJeSIxM31w1E4TfPpgNYF4el_mrG60-5CXR5_qvj5R3cXhtaWVxd3NsenRobWVp.7b9573d072e69a60a37fcb569c28485029ecb15b&amp;uuid=&amp;state=jLT9ScZ_wbo,&amp;&amp;cst=AiuY0DBWFJ5Hyx_fyvalFBAz-eRsSIq0KPSbkqWHxWcmFXPnb-WYFP0wWXEsdld5uvCyn-5x03pPTY22iFVtdw_IN-JH8UWhhBUNws6-s4SQp3krvjD-NTOrqEjC65J6JuH2lAaMaLQ0yG2cS14aQtEOvpX-He9EfABh9IbxBvwIN4D_B6muZ_NNnG3fK64_15DEtr6kCtwqniNxjv1Hizkq8ga2WOpOkvkWPnc3KW1osdZW6q3YQVaI68JFe7K6vhAO4iCZwaTgqG1A0X9WyD_Sb0K79FSHE6bD_8ljs4zd4TYOV80bgd3jCTBFPAhKfipz-9YVEqCG_PDpfRRaO6jM7jadWL_anN-28j6Vrjps7mwmO99R4G7juGNoZxBP3SREAAh1--fYFhWFQFZSatqG_2DQqxp9LImbDi2zVkM57_EdsPd76gXKA4ECvWJDgNralNxnAT1FQSJISuUfqQWXbiMZpAImkhR2bx_f4S2MOobxv8MvfVs-N3qbWPs2PxpYMyjQciAt9douHr1bIWaGdCNNUWHj4iH8CFYXRMti1taeqqpEyQFSz2wiw-XOLCOGgS2dumF3DOlX_vSPIKMTM4bJ5fsCb0QOLXN29s2jmdbHLhJ4t2PP52y-EtZvOC4LYqsHEZBddUqVEyCqkZkfz8RhGON50lmRMF0FkAGsJZVYhwJyr42yiM2uCbWSYymaAmD-EBPwgVNVX0WH_I8MhVEmyTegKWXksgumg3a0kglw42eu7gpwDkmyzB4AGvmb29PDDWODHBKKu2SE3E0_98bu7i0AKk91MVKWsS6j1vaG6Sis2Q-USd6aTjLD2Uz7U-ffmMEiaUm8IupPqFu8ENn7PDwssjz_1xB6rwF5jvzvb-7WYpN9EBK2Yqy5egmZX04cOLr7uxTuj7Hib1ovzDLjjmO4UAn5c5YIn-jbwqCrIJcw3PRdkaUQiKRDlTvIbSS7jpq53Gowr4JXGyCFN4bCL9zkrORRPWFwsaJzUdURQEqgVQ,,&amp;data=UlNrNmk5WktYejY4cHFySjRXSWhXSEVtVW1Vd2k4bEVHLXduR0pQeXlxbnZjZExEaW9nYmxoay0xSzBGa3Y0OFVJN3pldkRoTHVoR2QxelpXMklVUmxUTW5TWmpLZ0hiT25MWExFMGVaUzN0MXdMYnlRSDRfM2pfdXJYa2RuR1NqRkNzMUswZUJaOCw,&amp;sign=da2056c21db2b9c8c5b5f051b74db322&amp;keyno=0&amp;b64e=2&amp;ref=orjY4mGPRjk5boDnW0uvlrrd71vZw9kpuILuEi-MOSKhGrnlD5dwhaz-oSRHRuNgqHqX3DHFzZjaYzGZjEGV-alPltVgdr90&amp;l10n=ru&amp;cts=1677693728138%40%40events%3D%5B%7B%22event%22%3A%22click%22%2C%22id%22%3A%221_3ztdw01-01%22%2C%22cts%22%3A1677693728138%2C%22fast%22%3A%7B%22organic%22%3A1%7D%2C%22service%22%3A%22web%22%2C%22event-id%22%3A%22lepzj1jecj%22%7D%5D&amp;mc=2&amp;hdtime=1027.4\" rel=\"noopener noreferrer nofollow\">\u043f\u0438\u0441\u0430\u043b<\/a> \u0438 \u0441\u043d\u0438\u043c\u0430\u043b \u043f\u0440\u043e \u044d\u0442\u043e <a href=\"https:\/\/youtu.be\/iGrLNOzE_2Q\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u0434\u0435\u043e<\/a>, \u0447\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u044f \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u043e\u043f\u043e\u0440\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c docker \u043e\u0431\u0440\u0430\u0437;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c docker-compose;<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 <a href=\"https:\/\/github.com\/nginx-proxy\/nginx-proxy\" rel=\"noopener noreferrer nofollow\">nginx-proxy<\/a> c <a href=\"https:\/\/github.com\/nginx-proxy\/acme-companion\" rel=\"noopener noreferrer nofollow\">acme-companion<\/a>;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u043c <code>docker-compose up -d<\/code> \u0438 \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430, \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0435 Kubernetes \u0438 \u043d\u0435 \u0441\u0443\u043f\u0435\u0440 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430. \u041d\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430 VPS \u043d\u0430 400\u0440 \u0432 \u043c\u0435\u0441\u044f\u0446 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0434\u0435\u0441\u044f\u0442\u043e\u043a \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u0449\u0438\u0445 \u044d\u0442\u0430\u043f\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c <code>frontend<\/code> (html, js, css).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c <code>backend<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0441\u0443\u043d\u0443\u0442\u044c \u0432 <code>backend<\/code> \u0444\u0430\u0439\u043b\u044b \u0438\u0437 frontend \u0432 \u043f\u0430\u043f\u043a\u0443 <code>static<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c nginx \u043e\u0431\u0440\u0430\u0437, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0442\u0440\u0430\u0444\u0444\u0438\u043a \u043d\u0430 \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<\/li>\n<\/ol>\n<h4>Dockerfile \u0441 multi-stage build<\/h4>\n<p>\u0412\u00a0\u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e node 16\u00a0\u043d\u0430\u00a0\u0431\u0430\u0437\u0435 \u043e\u0431\u0440\u0430\u0437\u0430 alpine. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c <code>Dockerfile<\/code> \u0441\u043e \u0441\u0442\u0440\u043e\u0447\u0435\u043a<\/p>\n<pre><code class=\"dart\">FROM node:16-alpine as base-builder WORKDIR \/app<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c <code>frontend<\/code> \u2014 \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0441\u043e\u0431\u0440\u0430\u0442\u044c html, js, css.<\/p>\n<pre><code>FROM base-builder as build_fe WORKDIR \/app COPY .\/frontend\/package.json .\/frontend\/yarn.lock* .\/ RUN yarn install ADD .\/frontend .\/ RUN yarn generate<\/code><\/pre>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u043c \u043e\u0431\u0440\u0430\u0437\u0435 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 <code>frontend<\/code> \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/app\/dist<\/code><\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c <code>backend<\/code><\/p>\n<pre><code>FROM base-builder as build_be WORKDIR \/app COPY .\/backend\/package.json .\/backend\/yarn.lock* .\/ RUN yarn install ADD .\/backend .\/ RUN yarn build<\/code><\/pre>\n<p>\u0418 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 <code>backend<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430 3001\u00a0\u043f\u043e\u0440\u0442\u0443 \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b:<\/p>\n<pre><code>FROM node:16-alpine as finalNode WORKDIR \/app COPY --from=build_be \/app \/app COPY --from=build_fe \/app\/dist \/app\/static CMD yarn start<\/code><\/pre>\n<p><em>\u042f \u0434\u043e\u00a0\u043a\u043e\u043d\u0446\u0430 \u043d\u0435\u00a0\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0441\u044f \u0432\u00a0\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0438, \u0447\u0435\u0441\u0442\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438 \u043d\u0435\u00a0\u0434\u0435\u043b\u0430\u0442\u044c. \u0423\u00a0\u043d\u0430\u0441, \u0432\u00a0\u0438\u0442\u043e\u0433\u0435, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f backend, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u00a0\u2014 \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0447\u0438\u0439 docker\u2011\u043e\u0431\u0440\u0430\u0437 \u0441\u00a0\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u0435\u0437\u00a0nginx. \u041d\u043e\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u0432\u00a0\u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f<\/em><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0442\u0443 \u0447\u0430\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441 <code>nginx<\/code>:<\/p>\n<pre><code>FROM nginx:alpine as finalNginx WORKDIR \/usr\/share\/nginx\/html RUN rm -rf .\/* COPY --from=finalNode \/app\/static . COPY .\/docker\/nginx\/conf.conf \/etc\/nginx\/conf.d\/default.conf CMD [\"nginx\", \"-g\", \"daemon off;\"]<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>nginx<\/code> \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c \u043f\u0443\u0442\u0438:<\/p>\n<pre><code class=\"cmake\"># docker\/nginx\/conf.conf server {   listen 80 default_server; root \/usr\/share\/nginx\/html;    client_max_body_size 20M;    location \/ {     root   \/usr\/share\/nginx\/html;     index  index.html index.htm;     try_files $uri $uri\/ \/index.html;   }    location \/api {     proxy_set_header Host $host;     proxy_set_header X-Real-IP $remote_addr;     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;     proxy_set_header X-Forwarded-Proto $scheme;     proxy_pass http:\/\/node:3001;   } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b, \u0432\u00a0\u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e <code>Dockerfile<\/code> \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u0443\u044e \u0441\u0431\u043e\u0440\u043a\u0443 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e\u00a0\u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f\u00a0\u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p><a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\/blob\/master\/Dockerfile\" rel=\"noopener noreferrer nofollow\">\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 <\/a><code>Dockerfile<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u00a0github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<\/p>\n<h4>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 docker-compose.yml<\/h4>\n<p>\u041a\u0430\u043a\u00a0\u044f \u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435, \u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0430\u00a0\u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <code>nginx-proxy<\/code>. \u0422\u0430\u043a \u0447\u0442\u043e, \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c, \u0432\u00a0\u043a\u043e\u043d\u0446\u0435 \u0444\u0430\u0439\u043b\u0430 \u043d\u0430\u0434\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0441\u0435\u0442\u044c <code>reverse-proxy<\/code>, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u0438\u0434\u0442\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438\u0437\u00a0\u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043c\u0438\u0440\u0430 \u043a\u00a0\u043c\u043e\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0441 <code>nginx<\/code>.<\/p>\n<pre><code class=\"yaml\">version: \"3.8\" services: # \u0442\u0443\u0442 \u0431\u0443\u0434\u0443\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u044b networks:   reverse-proxy:     external:       name: reverse-proxy   back:     driver: bridge<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0441\u0435\u0442\u044c <code>back<\/code>\u00a0\u2014 \u044d\u0442\u043e \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0435\u0442\u044c, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f <code>nginx<\/code> \u0438 <code>backend<\/code>.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0438\u0448\u0435\u043c \u043a\u0430\u043a\u00a0\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0448 \u043e\u0431\u0440\u0430\u0437 \u0441\u00a0\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 <code>backend<\/code>:<\/p>\n<pre><code class=\"yaml\">node:   build:     context: .     target: finalNode   networks:     - back   expose:     - 3001   restart: always   environment:     - APP_PORT=3001   healthcheck:     test: wget --no-verbose --tries=1 --spider &lt;http:\/\/localhost:3001> || exit 1     timeout: 3s     interval: 3s     retries: 10 <\/code><\/pre>\n<p>\u041f\u043e\u00a0\u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u043e\u00a0\u043a\u0430\u0436\u0434\u043e\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435:<\/p>\n<ul>\n<li>\n<p><code>build<\/code> <\/p>\n<ul>\n<li>\n<p><code>context<\/code>\u00a0\u2014 \u0447\u0442\u043e\u00a0\u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0435\u0439 \u043f\u0440\u0438\u00a0\u0441\u0431\u043e\u0440\u043a\u0435 <code>Dockerfile<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>target<\/code>\u00a0\u2014 \u043a\u0430\u043a\u0443\u044e \u0447\u0430\u0441\u0442\u044c multi\u2011stage build \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432\u00a0\u044d\u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u0412\u00a0\u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e\u00a0\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u043e \u0432\u0441\u0435 \u0434\u043e <code>finalNode<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>networks<\/code> <\/p>\n<ul>\n<li>\n<p>\u0442\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e back, \u0442.\u043a. \u0432\u043e\u00a0\u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043c\u0438\u0440 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0435\u00a0\u0431\u0443\u0434\u0435\u0442 \u0438 \u043d\u0443\u0436\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u043e\u0442 <code>nginx<\/code> \u043a\u00a0\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>expose<\/code> <\/p>\n<ul>\n<li>\n<p>\u044d\u0442\u043e\u0442 \u043f\u0443\u043d\u043a\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u0440\u0443\u0433\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c \u0432\u00a0\u0441\u0435\u0442\u0438 \u043f\u043e\u00a0\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u0430\u043c. \u0412\u00a0\u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c, \u0447\u0442\u043e\u00a0\u0432\u00a0\u0441\u0435\u0442\u0438 back \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 3001\u00a0\u043f\u043e\u0440\u0442.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>restart: always<\/code> <\/p>\n<ul>\n<li>\n<p>\u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c, \u0447\u0442\u043e\u00a0\u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u0434\u0430. \u0414\u0430\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d;<\/p>\n<\/li>\n<li>\n<p>\u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0434\u043e\u00a0\u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u043d\u0435\u00a0\u0432\u044b\u043a\u043b\u044e\u0447\u0438\u043c \u0435\u0433\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>docker-compose down<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>environment<\/code> <\/p>\n<ul>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432\u00a0\u0441\u0430\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 node;<\/p>\n<\/li>\n<li>\n<p>\u0432\u00a0\u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0440\u0442, \u043d\u0430\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b <code>backend<\/code>\u00a0\u0431\u044b\u043b \u0437\u0430\u043f\u0443\u0449\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>healthcheck<\/code> <\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f\u00a0\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430;<\/p>\n<\/li>\n<li>\n<p><code>test<\/code>\u00a0\u2014 \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043e\u0442\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c <code>exit-code = 0<\/code> (\u043a\u0430\u043a\u0438\u0435 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/en.wikipedia.org\/wiki\/Exit_status\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>);<\/p>\n<\/li>\n<li>\n<p><code>timeout<\/code>\u00a0\u2014 \u0432\u0440\u0435\u043c\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430. \u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430\u0432\u0438\u0441\u043b\u0430 \u043d\u0430\u00a0\u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u0441\u0440\u043e\u043a, \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u00a0\u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043e\u0439;<\/p>\n<\/li>\n<li>\n<p><code>interval<\/code>\u00a0\u2014 \u0441\u00a0\u043a\u0430\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 \u0441\u0442\u043e\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443, \u0447\u0442\u043e\u0431\u044b\u00a0\u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c, \u0447\u0442\u043e\u00a0\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442;<\/p>\n<\/li>\n<li>\n<p><code>retries<\/code>\u00a0\u2014 \u043f\u043e\u0441\u043b\u0435 \u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u044b\u0445 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u043e\u043c\u0435\u0447\u0430\u0435\u0442\u0441\u044f \u00ab\u043d\u0435\u0440\u0430\u0431\u043e\u0447\u0438\u043c\u00bb.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0431\u043b\u043e\u043a \u0441\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c <code>nginx<\/code>:<\/p>\n<pre><code class=\"yaml\">nginx:   build:     context: .     target: finalNginx   networks:     - reverse-proxy     - back   expose:     - 80   restart: always   depends_on:     node:       condition: service_healthy   environment:     - VIRTUAL_HOST=${DOMAIN}     - VIRTUAL_PORT=80     - LETSENCRYPT_HOST=${DOMAIN}     - LETSENCRYPT_EMAIL=test@test.ru<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><code>build<\/code> \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0432 <code>node<\/code> \u0441\u0435\u0440\u0432\u0438\u0441\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043a\u0430\u0437\u0430\u043d \u0434\u0440\u0443\u0433\u043e\u0439 <code>target<\/code>, \u0442.\u043a. \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0443 \u0447\u0430\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 <code>nginx<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>networks<\/code> \u0442\u0443\u0442 \u0442\u0435\u043f\u0435\u0440\u044c 2 \u0441\u0435\u0442\u0438: <\/p>\n<ul>\n<li>\n<p><code>reverse-proxy<\/code> \u0441\u0435\u0442\u044c, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 <code>nginx-proxy<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>back<\/code> \u0442\u0430 \u0441\u0435\u0442\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 <code>node<\/code> \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0435\u043c\u0443.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>expose<\/code> \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u0432\u0441\u0435\u043c \u0432 \u0441\u0435\u0442\u044f\u0445, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 80 \u043f\u043e\u0440\u0442. \u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e <code>nginx-proxy<\/code> \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p><code>restart<\/code> \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0443 <code>node<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>depends_on<\/code> \u0442\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u0442 \u043a\u0430\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043c\u044b \u0437\u0430\u0432\u0438\u0441\u0438\u043c:<\/p>\n<ul>\n<li>\n<p>\u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0442\u043e nginx \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 <code>node<\/code> \u0435\u0449\u0435 \u043d\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d, \u0430 <code>nginx<\/code>  \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0447\u0442\u043e \u043d\u0435\u0445\u043e\u0440\u043e\u0448\u043e;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 <code>node<\/code>  \u0441\u0435\u0440\u0432\u0438\u0441\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u043e\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0448\u0435\u043b \u0441\u0432\u043e\u0439 <code>healthcheck<\/code> (\u043a\u0430\u043a \u0440\u0430\u0437 \u0431\u043b\u043e\u043a <code>condition<\/code>).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>environment<\/code> <\/p>\n<ul>\n<li>\n<p>\u0442\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b <code>nginx-proxy<\/code>: <\/p>\n<ul>\n<li>\n<p><code>VIRTUAL_HOST<\/code> \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043c\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e;<\/p>\n<\/li>\n<li>\n<p><code>VIRTUAL_PORT<\/code> \u043f\u043e\u0440\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435;<\/p>\n<\/li>\n<li>\n<p><code>LETSENCRYPT_HOST<\/code> \u0442\u043e\u0442 \u0436\u0435 \u0441\u0430\u043c\u044b\u0439 \u0434\u043e\u043c\u0435\u043d \u043d\u043e \u0443\u0436\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f https \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p><code>LETSENCRYPT_EMAIL<\/code> \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u0430\u044f \u043f\u043e\u0447\u0442\u0430, \u043a\u0443\u0434\u0430 \u043f\u0438\u0441\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0441\u043a\u043e\u0440\u043e \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0440\u043e\u0447\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u0442\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u044f\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <code>${DOMAIN}<\/code> \u0438 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <code>.env<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 <code>docker-compose.yml<\/code> \u0444\u0430\u0439\u043b\u043e\u043c (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/docs.docker.com\/compose\/environment-variables\/env-file\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\/blob\/master\/docker-compose.yml\" rel=\"noopener noreferrer nofollow\">\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 <\/a>\u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0444\u0430\u0439\u043b\u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<\/p>\n<h4>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0432 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0444\u0430\u0439\u043b <code>.dockerignore<\/code> \u0447\u0442\u043e\u0431\u044b, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0431\u043e\u0440\u043a\u0438, \u043d\u0435 \u043f\u0435\u0440\u0435\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043b\u0438\u0448\u043d\u0435\u0433\u043e:<\/p>\n<pre><code>#.dockerignore .idea .git **\/.nuxt **\/dist **\/.output **\/node_modules **\/.env<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043b <code>.env.example<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0430\u0439\u043b\u0430-\u043f\u0440\u0438\u043c\u0435\u0440\u0430:<\/p>\n<pre><code>DOMAIN=domain.ru<\/code><\/pre>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<h4>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h4>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0436\u0435 \u0441\u0442\u043e\u044f\u0442\u044c Docker. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0435\u0433\u043e \u043f\u043e\u00a0\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 <a href=\"https:\/\/docs.docker.com\/engine\/install\/\" rel=\"noopener noreferrer nofollow\">\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438<\/a>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u00a0\u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <code>nginx-proxy<\/code> \u0438 \u043b\u0443\u0447\u0448\u0435 \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u043d\u0430\u00a0\u0442\u043e\u043c\u2011\u0436\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f <a href=\"https:\/\/github.com\/nginx-proxy\/nginx-proxy#docker-compose\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>, \u043d\u043e\u00a0\u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e, \u0442\u043e \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0432\u00a0\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044e \u044d\u0442\u0443 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u0437\u0434\u0435\u0441\u044c).<\/p>\n<h4>\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u044d\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ol>\n<li>\n<p>\u041a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c <code>DOMAIN<\/code> \u0432 <code>.env<\/code> \u0444\u0430\u0439\u043b \u0432\u00a0\u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>docker-compose up -d<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0443\u0441\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<pre><code class=\"bash\">DOMAIN=domain.ru &amp;&amp; echo DOMAIN=$DOMAIN > .env &amp;&amp; docker-compose up -d --build<\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u043e: \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c <code>domain.ru<\/code> \u043d\u0430 \u0441\u0432\u043e\u0439 \u0434\u043e\u043c\u0435\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0433\u0434\u0435 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441.<\/p>\n<h4>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">git fetch &amp;&amp; git reset --hard origin\/master &amp;&amp; docker-compose up -d --build<\/code><\/pre>\n<p>\u0418 \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430\u00a0\u0434\u043e\u043c\u0435\u043d\u0435.<\/p>\n<h3>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u00a0\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u00a0Nuxt + Nest \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c. \u041e\u043d \u043a\u0440\u0430\u0439\u043d\u0435 \u043f\u0443\u0441\u0442\u00a0\u2014 \u043d\u0435\u0442 \u0411\u0414, \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0432\u0435\u0449\u0435\u0439. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u00a0\u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0435\u0441\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u043e\u00a0\u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u0447\u0430\u0442\u044c \u0441\u00a0\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u043a\u0443\u0434\u0430 \u0443\u0433\u043e\u0434\u043d\u043e.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d \u0434\u043b\u044f\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u0442\u043e \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043e\u043f\u0438\u0448\u0443 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u00a0\u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 (Postgres) \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 (JWT). \u0422\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u044b\u0441\u043b\u044c \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 ansible \u0434\u043b\u044f\u00a0\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u00a0\u0441\u0432\u043e\u0435\u043c\u00a0\u043b\u0438\u0447\u043d\u043e\u043c \u0431\u043b\u043e\u0433\u0435 \u0432\u00a0\u0440\u0443\u0431\u0440\u0438\u043a\u0435 <a href=\"https:\/\/amorev.ru\/category\/razrabotka\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/a> \u043f\u0438\u0448\u0443 \u0440\u0430\u0437\u043d\u044b\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438 \u0434\u0435\u043b\u044e\u0441\u044c \u043e\u043f\u044b\u0442\u043e\u043c \u043d\u0430\u00a0\u0441\u0432\u043e\u0435\u043c <a href=\"https:\/\/youtube.com\/amorev\" rel=\"noopener noreferrer nofollow\">Youtube \u043a\u0430\u043d\u0430\u043b\u0435<\/a> \u0438 <a href=\"https:\/\/t.me\/gmoreva\" rel=\"noopener noreferrer nofollow\">Telegram<\/a>.<\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430\u00a0\u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \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\/post\/720000\/\"> https:\/\/habr.com\/ru\/post\/720000\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0420\u0435\u0448\u0438\u043b \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u00a0Typescript \u0441\u00a0Nest \u043d\u0430\u00a0\u0431\u0435\u043a\u0435\u043d\u0434\u0435, Nuxt (SPA) \u043d\u0430\u00a0\u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435. \u0412\u0441\u0435 \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u043e\u0434\u0438\u043d docker\u2011\u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a\u00a0standalone \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 c nginx, healthcheck\u00bb\u0430\u043c\u0438, \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0448\u2026\u0448\u0438\u0440\u043e\u043a\u043e\u0439 \u0441\u0444\u0435\u0440\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0435\u043b\u0430\u043b \u044d\u0442\u043e \u0432\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f\u00a0\u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438\u043b\u0438\u00a0\u0441\u00a0\u0446\u0435\u043b\u044c\u044e \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f Nest, Nuxt 3\u00a0\u0441\u00a0composable \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043a\u0430\u043a\u00a0\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043a\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0437\u0430\u00a0\u043e\u0441\u043d\u043e\u0432\u0443 \u043a\u043e\u0434 \u0441 <a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\" rel=\"noopener noreferrer nofollow\">github<\/a>.<\/p>\n<h3>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0428\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u00a0\u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u0433\u043e docker\u2011\u043e\u0431\u0440\u0430\u0437\u0430, \u0432\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <code>nest<\/code>+<code>nginx<\/code> \u0438 \u0441\u043e\u0431\u0440\u0430\u043d\u044b <code>backend<\/code> \u0438 <code>frontend<\/code>.<\/p>\n<figure class=\"full-width\"><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/figcaption><\/figure>\n<h4>\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0443 \u0438\u0437 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<pre><code>\u2514\u2500\u2500 application\/     \u251c\u2500\u2500 backend\/     \u2502   \u2514\u2500\u2500 NEST \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     \u251c\u2500\u2500 frontend\/     \u2502   \u2514\u2500\u2500 NUXT \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     \u251c\u2500\u2500 docker\/     \u2502   \u2514\u2500\u2500 nginx\/     \u2502       \u2514\u2500\u2500 conf.conf     \u251c\u2500\u2500 .dockerignore     \u251c\u2500\u2500 .gitignore     \u251c\u2500\u2500 docker-compose.yml     \u251c\u2500\u2500 Dockerfile     \u2514\u2500\u2500 readme.md<\/code><\/pre>\n<ul>\n<li>\n<p><code>backend<\/code> \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c <a href=\"https:\/\/github.com\/nestjs\/serve-static\" rel=\"noopener noreferrer nofollow\">serve-static<\/a> \u043c\u043e\u0434\u0443\u043b\u0435\u043c;<\/p>\n<\/li>\n<li>\n<p><code>frontend<\/code> \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 nuxt \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u044c\u044e \u0441 <code>backend<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>docker<\/code> \u2014 \u043f\u0430\u043f\u043a\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0439\u0434\u0443\u0442 \u0432 docker \u043e\u0431\u0440\u0430\u0437 (\u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u043e\u043b\u044c\u043a\u043e nginx);<\/p>\n<\/li>\n<li>\n<p><code>Dockerfile<\/code> \u2014 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043f\u043e \u0441\u0431\u043e\u0440\u043a\u0435 \u0434\u043e\u043a\u0435\u0440-\u043e\u0431\u0440\u0430\u0437\u0430;<\/p>\n<\/li>\n<li>\n<p><code>docker-compose.yml<\/code> \u2014 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/wormsoft\/nest-and-nuxt-starter-kit\" rel=\"noopener noreferrer nofollow\">github<\/a>, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>docker-compose up -d<\/code> (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e\u00a0\u0437\u0430\u043f\u0443\u0441\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0432\u00a0\u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438) \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u00a0\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0438\u0436\u0435 \u044f \u043e\u043f\u0438\u0441\u0430\u043b \u0447\u0442\u043e\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043e \u0432\u00a0\u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0438 \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438<\/p>\n<blockquote>\n<p>\u0412\u00a0\u044d\u0442\u043e\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u043d\u0435\u0442 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043a\u0430\u043a\u0438\u0445\u2011\u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/blockquote>\n<h4>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/h4>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Nginx. \u041e\u043d \u0440\u0430\u0437\u0434\u0430\u0435\u0442 \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0431\u0435\u043a\u0435\u043d\u0434, \u0435\u0441\u043b\u0438 URL \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>\/api<\/code><\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 2 \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0418 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Backend \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0437\u044f\u0442 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 <a href=\"https:\/\/docs.nestjs.com\/\" rel=\"noopener noreferrer nofollow\">nest<\/a>:<\/p>\n<pre><code class=\"bash\">$ npm i -g @nestjs\/cli $ nest new backend<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0432 <code>main.ts<\/code> \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0440\u0442 \u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0430 3001, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>\/api<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c <code>main.ts<\/code> \u043e\u0431\u0440\u0435\u0442\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"typescript\">import { NestFactory } from '@nestjs\/core'; import { AppModule } from '.\/app.module';  async function bootstrap() {   const app = await NestFactory.create(AppModule);   const port = process.env.APP_PORT || 3001;   app.setGlobalPrefix('api');   app.enableCors();   await app.listen(port); } bootstrap();<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 static \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438<\/h4>\n<p>\u0412\u00a0\u043f\u0430\u043f\u043a\u0443 static \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 html\/js\/css \u0431\u0430\u043d\u0434\u043b \u0441\u00a0nuxt \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a\u00a0\u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0435\u0437\u00a0nginx.<\/p>\n<blockquote>\n<p>\u0414\u0430, \u043f\u0440\u0438\u00a0\u043f\u0440\u043e\u0447\u0438\u0445 \u0440\u0430\u0432\u043d\u044b\u0445, \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u00a0nginx \u0438 \u0434\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u043d\u0435\u00a0\u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0432\u00a0\u043f\u0430\u043f\u043a\u0443 static \u043d\u0438\u0447\u0435\u0433\u043e.<\/p>\n<p>\u041d\u043e\u00a0\u043d\u0430 \u0442\u043e \u044d\u0442\u043e \u0438 \u0431\u043e\u0439\u043b\u0435\u0440, \u0447\u0442\u043e\u00a0\u044f \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435\u00a0\u0437\u043d\u0430\u044e \u043a\u0430\u043a\u00a0\u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438 \u0433\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f. \u041c\u043e\u0436\u0435\u0442\u00a0\u0431\u044b\u0442\u044c, \u0432\u00a0\u043a\u0430\u043a\u0438\u0445 \u0442\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u043f\u0440\u0438\u00a0\u043c\u0430\u043b\u044b\u0445 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u0445, \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0438\u0441\u0442\u043e\u0433\u043e Nest.<\/p>\n<\/blockquote>\n<p>\u0414\u043b\u044f\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b nest \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u043b \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/nestjs\/serve-static\" rel=\"noopener noreferrer nofollow\">serve\u2011static<\/a> \u0432\u043d\u0443\u0442\u0440\u044c <code>AppModule<\/code><\/p>\n<pre><code class=\"typescript\">import { Module } from '@nestjs\/common'; import { AppController } from '.\/app.controller'; import { AppService } from '.\/app.service'; import { ServeStaticModule } from '@nestjs\/serve-static'; import * as path from 'path';  @Module({   imports: [     ServeStaticModule.forRoot({       rootPath: path.join(__dirname, '..', 'static'),       serveRoot: '\/',       exclude: ['\/api*'],     }),   ],   controllers: [AppController],   providers: [AppService], }) export class AppModule {}<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0\u0431\u043b\u043e\u043a <code>exclude: ['\/api*']<\/code>. \u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0442\u0430\u0442\u0438\u043a\u0430 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u043d\u0430\u00a0\u0432\u0441\u0435\u0445 \u0441\u0441\u044b\u043b\u043a\u0430\u0445, \u043a\u0440\u043e\u043c\u0435 <code>\/api<\/code>\u00a0\u2014 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u00a0\u043f\u0443\u0442\u0438 <code>\/api<\/code> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0441\u0430\u043c\u043e nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0412\u00a0\u0441\u0430\u043c\u0443 \u043f\u0430\u043f\u043a\u0443 static \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c <code>.gitignore<\/code> \u0441\u00a0\u0434\u0432\u0443\u043c\u044f \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c\u0438:<\/p>\n<pre><code>* !index.html<\/code><\/pre>\n<p>\u0418 index.html, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0432 \u044d\u0442\u0443 \u043f\u0430\u043f\u043a\u0443 \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f html\/js\/css \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<h4>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430 \u043a api<\/h4>\n<p>\u0412 nest \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>\/api<\/code> \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 \u043f\u0440\u0438\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c <code>\/api<\/code> \u0432 <code>@Controller('\/api\/controller-route')<\/code><\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 nest \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441<\/p>\n<\/li>\n<\/ul>\n<p>\u042f \u0432 \u0441\u0432\u043e\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0432\u0442\u043e\u0440\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u0414\u043b\u044f \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 <code>main.ts<\/code> \u0441\u0442\u0440\u043e\u0447\u043a\u0443 <code>app.setGlobalPrefix('api');<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c e2e \u0442\u0435\u0441\u0442, \u0447\u0442\u043e\u0431\u044b \u0432 \u043d\u0435\u043c \u0442\u043e\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 e2e \u0442\u0435\u0441\u0442\u044b \u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e, \u044f \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u043d\u043e\u0448\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">export async function createTestingApp() { return (   await Test.createTestingModule({     imports: [AppModule],   }).compile() )   .createNestApplication()   .setGlobalPrefix('api'); }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u044f \u0443\u0436\u0435, \u0432 \u0442\u0435\u0441\u0442\u0430\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u043c\u0435\u0441\u0442\u043e \u0448\u0442\u0430\u0442\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">import { createTestingApp } from '.\/utils\/create-testing-app';  \/\/ .....  beforeEach(async () => {   app = await createTestingApp();   await app.init(); });<\/code><\/pre>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u042f \u0443\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0432\u00a0\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0431\u043b\u043e\u043a\u0435, \u043d\u043e\u00a0\u043f\u043e\u00a0\u0442\u0435\u0441\u0442\u0430\u043c \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0435\u0449\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<ul>\n<li>\n<p>\u0443\u0434\u0430\u043b\u0438\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 spec \u0444\u0430\u0439\u043b \u0443\u00a0\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u0442.\u043a. \u0441\u0430\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e e2e \u0442\u0435\u0441\u0442\u044b \u0438 \u0443\u0437\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0448\u0443 \u0432\u00a0\u0440\u0435\u0434\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043c\u0435\u043d\u044f\u043b \u0444\u043e\u0440\u043c\u0430\u0442 <code>jest.e2e.config.json<\/code> \u043d\u0430 <code>js<\/code>, \u0442\u043a, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e, \u0432\u00a0\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 IDE js \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043b \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0442\u0435\u0441\u0442 \u0441\u00a0\u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c <code>\/api<\/code> \u0432\u00a0\u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Frontend<\/h3>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f Nuxt 3 \u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443<\/p>\n<pre><code class=\"bash\">yarn create nuxt-app frontend<\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u044f \u043d\u0435\u00a0\u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Nuxt \u0441\u00a0SSR, \u0442.\u043a. \u0443\u00a0\u043c\u0435\u043d\u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0447\u0438\u0441\u0442\u043e SPA \u043f\u043e\u0434\u0445\u043e\u0434 (\u043a\u043e\u0433\u0434\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u043a\u00a0\u0441\u0435\u0431\u0435 \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0443\u0436\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441).<\/p>\n<p>\u0414\u0430, SSR \u043a\u043b\u0430\u0441\u0441\u043d\u043e \u0438 \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043d\u043e\u00a0\u0441\u0447\u0438\u0442\u0430\u044e \u0435\u0433\u043e \u0443\u043c\u0435\u0441\u0442\u043d\u044b\u043c \u0432\u00a0\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0441\u00a0\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c SEO \u0438\u043b\u0438\u00a0\u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0447\u0430\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043a\u0440\u044b\u0442\u044c \u043e\u0442\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0435\u2011\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f).<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u00a0\u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u0440\u0438\u00a0\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u00ab\u043f\u0435\u0440\u0435\u043e\u0431\u0443\u0442\u044c\u00bb \u043d\u0430\u00a0\u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u00a0SSR. \u0427\u0442\u043e\u00a0\u0431\u044b \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c SSR \u0440\u0435\u0436\u0438\u043c \u043d\u0430\u0434\u043e \u0432 <code>nuxt.config.ts<\/code> \u0443\u043a\u0430\u0437\u0430\u0442\u044c <code>ssr: false<\/code><\/p>\n<h4>\u041f\u0430\u0440\u0430 \u0441\u043b\u043e\u0432 \u043f\u0440\u043e Options \u0438 Composition<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0434\u0430\u0432\u043d\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441\u00a0Vue, \u0442\u043e \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e\u00a0\u0440\u0430\u043d\u044c\u0448\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043c\u043e\u0436\u043d\u043e\u00a0\u0431\u044b\u043b\u043e \u0434\u0435\u043b\u0430\u0442\u044c vue \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 Options \u043f\u043e\u0434\u0445\u043e\u0434 (\u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u00a0\u043f\u043e\u043b\u044f\u043c\u0438 data, computed \u0438 \u0442\u0434). \u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437 setup \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u043c\u043d\u0435 \u0434\u043e\u00a0\u043a\u043e\u043d\u0446\u0430 \u043d\u0435\u00a0\u044f\u0441\u043d\u044b \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<p>\u042f\u00a0\u0436\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f, \u043f\u043e\u043a\u0430 \u0447\u0442\u043e, \u043d\u0430\u00a0\u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0447\u0435\u0440\u0435\u0437 options \u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u044f\u044e compose \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u00a0\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445. \u0412\u00a0\u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043d\u0430\u0431\u043e\u0440\u0435 \u044f \u0432\u044b\u0431\u0440\u0430\u043b Composition \u043f\u043e\u0434\u0445\u043e\u0434, \u0442.\u043a. \u0442\u0443\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0442 \u0438 \u0437\u0430\u043e\u0434\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c.<\/p>\n<h4>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 NuxtPage<\/h4>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0432 <code>App.vue<\/code> \u043d\u0435\u00a0\u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d <code>NuxtPage<\/code> \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0439\u043b\u044b \u0432 <code>pages<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435\u00a0\u0431\u0443\u0434\u0435\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <code>App.Vue<\/code> \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0432\u0438\u0434\u0443:<\/p>\n<pre><code class=\"xml\">&lt;template>   &lt;div>     &lt;NuxtPage \/>   &lt;\/div> &lt;\/template><\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u00a0\u043f\u0430\u043f\u043a\u0435 <code>pages\/<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u00a0\u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u0432\u00a0\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/nuxt.com\/docs\/guide\/directory-structure\/pages\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h4>\u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043a API<\/h4>\n<p>\u0414\u043b\u044f\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441\u2011\u043b\u043e\u0433\u0438\u043a\u0438 \u0432\u043e\u00a0Vue 3\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/vuejs.org\/guide\/reusability\/composables.html\" rel=\"noopener noreferrer nofollow\">Composable<\/a> \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0420\u0430\u043d\u044c\u0448\u0435 \u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u043b \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0432\u0435\u0449\u0438 \u0432\u00a0\u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u0441\u00a0\u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439 \u0445\u0435\u0434\u0435\u0440\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 + \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f baseUrl \u0438\u0437\u00a0env \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439.<\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u044f \u0441\u0434\u0435\u043b\u0430\u044e \u043f\u043e\u2011\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0439 composable \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0449\u0435\u0439 <code>useFetch<\/code>. \u0412\u00a0Nuxt composables \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f <a href=\"https:\/\/nuxt.com\/docs\/guide\/directory-structure\/composables\" rel=\"noopener noreferrer nofollow\">\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438<\/a>, \u0441\u043e\u0437\u0434\u0430\u0432 \u0444\u0430\u0439\u043b \u0432\u00a0\u043f\u0430\u043f\u043a\u0435 <code>composables<\/code>.<\/p>\n<pre><code class=\"typescript\">\/\/ frontend\/composables\/api.ts import { UseFetchOptions } from '#app'; import { NitroFetchRequest } from 'nitropack'; import { KeyOfRes } from 'nuxt\/dist\/app\/composables\/asyncData';  export function useApiRequest&lt;T>(   request: NitroFetchRequest,   opts?:     | UseFetchOptions&lt;T extends void ? unknown : T,     (res: T extends void ? unknown : T) => T extends void ? unknown : T,     KeyOfRes&lt;(res: T extends void ? unknown : T) => T extends void ? unknown : T>>     | undefined ) {   const config = useRuntimeConfig();    return useFetch(request, {baseURL: config.public.baseURL, ...opts}); }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f <code>config.public.baseURL<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c <code>nuxt.config.ts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"typescript\">export default defineNuxtConfig({   ssr: false,   runtimeConfig: {     public: {       baseURL: process.env.API_URL || 'http:\/\/localhost:3001\/',     },   }, }) <\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c, \u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, <code>baseURL<\/code> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u0435\u043d <code>http:\/\/localhost:3001\/<\/code>, \u0447\u0442\u043e\u0431\u044b, \u043f\u0440\u0438\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 Nest. \u041f\u0440\u0438\u00a0\u0441\u0431\u043e\u0440\u043a\u0435 \u0431\u0443\u0434\u0443 \u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 <code>\/api<\/code>.<\/p>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f API \u0432\u044b\u0437\u043e\u0432\u0430<\/h4>\n<p>\u0412\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0432\u00a0\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 \u0432 <code>\/api\/test<\/code> \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u00a0\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 \u0432\u0441\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code class=\"typescript\">&lt;template>   &lt;div>     &lt;template v-if=\"pending\">       Loading     &lt;\/template>     &lt;template v-else>       &lt;template v-if=\"data\">         Api result: {{ data }}       &lt;\/template>       &lt;template v-else-if=\"error\">         Api ERROR: {{ error }}       &lt;\/template>       &lt;button @click=\"refresh()\">refresh&lt;\/button>     &lt;\/template>   &lt;\/div> &lt;\/template>  &lt;script setup> import { useApiRequest } from '..\/composables\/api'  const { data, pending, error, refresh } = useApiRequest('\/api\/test') &lt;\/script><\/code><\/pre>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0438 docker-compose.yml<\/h3>\n<p>\u0412 \u0441\u0432\u043e\u0435\u043c \u043b\u0438\u0447\u043d\u043e\u043c \u0431\u043b\u043e\u0433\u0435 \u044f <a href=\"https:\/\/yandex.ru\/clck\/jsredir?from=yandex.ru%3Bsearch%2F%3Bweb%3B%3B&amp;text=&amp;etext=2202._IJeSIxM31w1E4TfPpgNYF4el_mrG60-5CXR5_qvj5R3cXhtaWVxd3NsenRobWVp.7b9573d072e69a60a37fcb569c28485029ecb15b&amp;uuid=&amp;state=jLT9ScZ_wbo,&amp;&amp;cst=AiuY0DBWFJ5Hyx_fyvalFBAz-eRsSIq0KPSbkqWHxWcmFXPnb-WYFP0wWXEsdld5uvCyn-5x03pPTY22iFVtdw_IN-JH8UWhhBUNws6-s4SQp3krvjD-NTOrqEjC65J6JuH2lAaMaLQ0yG2cS14aQtEOvpX-He9EfABh9IbxBvwIN4D_B6muZ_NNnG3fK64_15DEtr6kCtwqniNxjv1Hizkq8ga2WOpOkvkWPnc3KW1osdZW6q3YQVaI68JFe7K6vhAO4iCZwaTgqG1A0X9WyD_Sb0K79FSHE6bD_8ljs4zd4TYOV80bgd3jCTBFPAhKfipz-9YVEqCG_PDpfRRaO6jM7jadWL_anN-28j6Vrjps7mwmO99R4G7juGNoZxBP3SREAAh1--fYFhWFQFZSatqG_2DQqxp9LImbDi2zVkM57_EdsPd76gXKA4ECvWJDgNralNxnAT1FQSJISuUfqQWXbiMZpAImkhR2bx_f4S2MOobxv8MvfVs-N3qbWPs2PxpYMyjQciAt9douHr1bIWaGdCNNUWHj4iH8CFYXRMti1taeqqpEyQFSz2wiw-XOLCOGgS2dumF3DOlX_vSPIKMTM4bJ5fsCb0QOLXN29s2jmdbHLhJ4t2PP52y-EtZvOC4LYqsHEZBddUqVEyCqkZkfz8RhGON50lmRMF0FkAGsJZVYhwJyr42yiM2uCbWSYymaAmD-EBPwgVNVX0WH_I8MhVEmyTegKWXksgumg3a0kglw42eu7gpwDkmyzB4AGvmb29PDDWODHBKKu2SE3E0_98bu7i0AKk91MVKWsS6j1vaG6Sis2Q-USd6aTjLD2Uz7U-ffmMEiaUm8IupPqFu8ENn7PDwssjz_1xB6rwF5jvzvb-7WYpN9EBK2Yqy5egmZX04cOLr7uxTuj7Hib1ovzDLjjmO4UAn5c5YIn-jbwqCrIJcw3PRdkaUQiKRDlTvIbSS7jpq53Gowr4JXGyCFN4bCL9zkrORRPWFwsaJzUdURQEqgVQ,,&amp;data=UlNrNmk5WktYejY4cHFySjRXSWhXSEVtVW1Vd2k4bEVHLXduR0pQeXlxbnZjZExEaW9nYmxoay0xSzBGa3Y0OFVJN3pldkRoTHVoR2QxelpXMklVUmxUTW5TWmpLZ0hiT25MWExFMGVaUzN0MXdMYnlRSDRfM2pfdXJYa2RuR1NqRkNzMUswZUJaOCw,&amp;sign=da2056c21db2b9c8c5b5f051b74db322&amp;keyno=0&amp;b64e=2&amp;ref=orjY4mGPRjk5boDnW0uvlrrd71vZw9kpuILuEi-MOSKhGrnlD5dwhaz-oSRHRuNgqHqX3DHFzZjaYzGZjEGV-alPltVgdr90&amp;l10n=ru&amp;cts=1677693728138%40%40events%3D%5B%7B%22event%22%3A%22click%22%2C%22id%22%3A%221_3ztdw01-01%22%2C%22cts%22%3A1677693728138%2C%22fast%22%3A%7B%22organic%22%3A1%7D%2C%22service%22%3A%22web%22%2C%22event-id%22%3A%22lepzj1jecj%22%7D%5D&amp;mc=2&amp;hdtime=1027.4\" rel=\"noopener noreferrer nofollow\">\u043f\u0438\u0441\u0430\u043b<\/a> \u0438 \u0441\u043d\u0438\u043c\u0430\u043b \u043f\u0440\u043e \u044d\u0442\u043e <a href=\"https:\/\/youtu.be\/iGrLNOzE_2Q\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u0434\u0435\u043e<\/a>, \u0447\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u044f \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u043e\u043f\u043e\u0440\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c docker \u043e\u0431\u0440\u0430\u0437;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c docker-compose;<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 <a href=\"https:\/\/github.com\/nginx-proxy\/nginx-proxy\" rel=\"noopener noreferrer nofollow\">nginx-proxy<\/a> c <a href=\"https:\/\/github.com\/nginx-proxy\/acme-companion\" rel=\"noopener noreferrer nofollow\">acme-companion<\/a>;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u043c <code>docker-compose up -d<\/code> \u0438 \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430, \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0435 Kubernetes \u0438 \u043d\u0435 \u0441\u0443\u043f\u0435\u0440 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430. \u041d\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430 VPS \u043d\u0430 400\u0440 \u0432 \u043c\u0435\u0441\u044f\u0446 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0434\u0435\u0441\u044f\u0442\u043e\u043a \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u0449\u0438\u0445 \u044d\u0442\u0430\u043f\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c <code>frontend<\/code> (html, js, css).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c <code>backend<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0441\u0443\u043d\u0443\u0442\u044c \u0432 <code>backend<\/code> \u0444\u0430\u0439\u043b\u044b \u0438\u0437 frontend \u0432 \u043f\u0430\u043f\u043a\u0443 <code>static<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c nginx \u043e\u0431\u0440\u0430\u0437, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0442\u0440\u0430\u0444\u0444\u0438\u043a \u043d\u0430 \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<\/li>\n<\/ol>\n<h4>Dockerfile \u0441 multi-stage build<\/h4>\n<p>\u0412\u00a0\u043f\u0440\u043e\u0435\u043a\u0442<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-346172","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/346172","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=346172"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/346172\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=346172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=346172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=346172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}