DEV Community

ILshat Khamitov
ILshat Khamitov

Posted on • Edited on

Manual deployment of NestJS and Angular applications on a dedicated server via "Docker Compose" and "PM2"

We buy a dedicated server and configure SSH access to it from a local computer.

Adding https://github.com/SteveLTN/https-portal in "Docker compose" for automatic generation and renewal of certificates.

1. Find a free or buy a dedicated server

I will not describe the steps on this point, I have already described them earlier in the "Buy VPS" section of another post - Deploy nestjs project to VPS with dokku.

As part of the current posts, I bought the cheapest dedicated server on the same site.

Operating system: Ubuntu 22.04 x64
Access to the world: 100 MB/sec (shared)
RAM: 2GB
CPU: 2 vCPUs
Number of IPv4 address: 1

When buying a dedicated server, I was also given a third-level domain: vps1724252356.tech0.ru in the future, this project will move to the domain https://fullstack.nestjs-mod.com .

2. After purchase, you need to set a password if it has not been set, different sites have their own interfaces for this, in my case, setting the password is on the page https://ztv.su/clientarea.php?action=productdetails&id=33376#tabChangepw .

We copy our local public SSH to a remote server, at startup you will be prompted to enter a password, you need to enter your password and press "Enter".

If there was no SSH key on the computer, then you need to create it using the ssh-keygen command

Commands

ssh-copy-id root@194.226.49.162 
Enter fullscreen mode Exit fullscreen mode

Console output
$ ssh-copy-id root@194.226.49.162 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_rsa.pub" The authenticity of host '194.226.49.162 (194.226.49.162)' can't be established. ECDSA key fingerprint is SHA256:SOME_SYMBOLS. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@194.226.49.162's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@194.226.49.162'" and check to make sure that only the key(s) you wanted were added. 
Enter fullscreen mode Exit fullscreen mode

3. Connecting to a remote server

Commands

ssh root@194.226.49.162 
Enter fullscreen mode Exit fullscreen mode

Console output
$ ssh root@194.226.49.162 Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-91-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Wed Aug 21 18:42:37 MSK 2024 System load: 0.02734375 Processes: 103 Usage of /: 9.4% of 24.05GB Users logged in: 0 Memory usage: 10% IPv4 address for eth0: 194.226.49.162 Swap usage: 0% * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s just raised the bar for easy, resilient and secure K8s cluster deployment. https://ubuntu.com/engage/secure-kubernetes-at-the-edge Expanded Security Maintenance for Applications is not enabled. 0 updates can be applied immediately. Enable ESM Apps to receive additional future security updates. See https://ubuntu.com/esm or run: sudo pro status The list of available updates is more than a week old. To check for new updates run: sudo apt update Last login: Wed Aug 21 18:41:46 2024 from X.X.X.X root@vps1724252356:~# 
Enter fullscreen mode Exit fullscreen mode

4. Installing all necessary packages on a dedicated server

Commands

sudo snap install curl curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh sudo groupadd docker sudo usermod -aG docker $USER sudo apt install git -y curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use nvm install v20 nvm use v20 npm install --global yarn sudo apt install default-jre -y sudo apt install -y unzip echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p sudo reboot 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~# sudo snap install curl curl 8.1.2 from Wouter van Bommel (woutervb) installed root@vps1724252356:~# curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh sudo groupadd docker sudo usermod -aG docker $USER # Executing docker install script, commit: 0d6f72e671ba87f7aa4c6991646a1a5b9f9dae84 + sh -c apt-get update -qq >/dev/null + sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ca-certificates curl >/dev/null + sh -c install -m 0755 -d /etc/apt/keyrings + sh -c curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" -o /etc/apt/keyrings/docker.asc + sh -c chmod a+r /etc/apt/keyrings/docker.asc + sh -c echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu jammy stable" > /etc/apt/sources.list.d/docker.list + sh -c apt-get update -qq >/dev/null + sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-ce-rootless-extras docker-buildx-plugin >/dev/null + sh -c docker version Client: Docker Engine - Community Version: 27.1.2 API version: 1.46 Go version: go1.21.13 Git commit: d01f264 Built: Mon Aug 12 11:50:12 2024 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 27.1.2 API version: 1.46 (minimum version 1.24) Go version: go1.21.13 Git commit: f9522e5 Built: Mon Aug 12 11:50:12 2024 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.7.20 GitCommit: 8fc6bcff51318944179630522a095cc9dbf9f353 runc: Version: 1.1.13 GitCommit: v1.1.13-0-g58aa920 docker-init: Version: 0.19.0 GitCommit: de40ad0 ================================================================================ To run Docker as a non-privileged user, consider setting up the Docker daemon in rootless mode for your user: dockerd-rootless-setuptool.sh install Visit https://docs.docker.com/go/rootless/ to learn about rootless mode. To run the Docker daemon as a fully privileged service, but granting non-root users access, refer to https://docs.docker.com/go/daemon-access/ WARNING: Access to the remote API on a privileged Docker daemon is equivalent to root access on the host. Refer to the 'Docker daemon attack surface' documentation for details: https://docs.docker.com/go/attack-surface/ ================================================================================ groupadd: group 'docker' already exists root@vps1724252356:~# sudo apt install git -y Reading package lists... Done Building dependency tree... Done Reading state information... Done Suggested packages: git-daemon-run | git-daemon-sysvinit git-doc git-email git-gui gitk gitweb git-cvs git-mediawiki git-svn The following packages will be upgraded: git 1 upgraded, 0 newly installed, 0 to remove and 137 not upgraded. Need to get 3165 kB of archives. After this operation, 16.4 kB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 git amd64 1:2.34.1-1ubuntu1.11 [3165 kB] Fetched 3165 kB in 1s (2408 kB/s) (Reading database ... 94596 files and directories currently installed.) Preparing to unpack .../git_1%3a2.34.1-1ubuntu1.11_amd64.deb ... Unpacking git (1:2.34.1-1ubuntu1.11) over (1:2.34.1-1ubuntu1.10) ... Setting up git (1:2.34.1-1ubuntu1.11) ... Scanning processes... Scanning linux images... Running kernel seems to be up-to-date. No services need to be restarted. No containers need to be restarted. No user sessions are running outdated binaries. No VM guests are running outdated hypervisor (qemu) binaries on this host. root@vps1724252356:~# curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use nvm install v20 nvm use v20 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 15037 100 15037 0 0 36871 0 --:--:-- --:--:-- --:--:-- 36945 => Downloading nvm from git to '/root/.nvm' => Cloning into '/root/.nvm'... remote: Enumerating objects: 376, done. remote: Counting objects: 100% (376/376), done. remote: Compressing objects: 100% (320/320), done. remote: Total 376 (delta 46), reused 176 (delta 29), pack-reused 0 (from 0) Receiving objects: 100% (376/376), 372.57 KiB | 2.13 MiB/s, done. Resolving deltas: 100% (46/46), done. * (HEAD detached at FETCH_HEAD) master => Compressing and cleaning up git repository => Appending nvm source string to /root/.bashrc => Appending bash_completion source string to /root/.bashrc => Close and reopen your terminal to start using nvm or run the following to use it now: export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion Downloading and installing node v20.16.0... Downloading https://nodejs.org/dist/v20.16.0/node-v20.16.0-linux-x64.tar.xz... ################################################################################################################################################################ 100.0% Computing checksum with sha256sum Checksums matched! Now using node v20.16.0 (npm v10.8.1) Creating default alias: default -> v20 (-> v20.16.0) Now using node v20.16.0 (npm v10.8.1) root@vps1724252356:~# npm install --global yarn added 1 package in 2s npm notice npm notice New patch version of npm available! 10.8.1 -> 10.8.2 npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2 npm notice To update run: npm install -g npm@10.8.2 npm notice root@vps1724252356:~# sudo apt install -y unzip Reading package lists... Done Building dependency tree... Done Reading state information... Done Suggested packages: zip The following NEW packages will be installed: unzip 0 upgraded, 1 newly installed, 0 to remove and 137 not upgraded. Need to get 175 kB of archives. After this operation, 386 kB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 unzip amd64 6.0-26ubuntu3.2 [175 kB] Fetched 175 kB in 0s (485 kB/s) Selecting previously unselected package unzip. (Reading database ... 96234 files and directories currently installed.) Preparing to unpack .../unzip_6.0-26ubuntu3.2_amd64.deb ... Unpacking unzip (6.0-26ubuntu3.2) ... Setting up unzip (6.0-26ubuntu3.2) ... Processing triggers for man-db (2.10.2-1) ... Scanning processes... Scanning linux images... Running kernel seems to be up-to-date. No services need to be restarted. No containers need to be restarted. No user sessions are running outdated binaries. No VM guests are running outdated hypervisor (qemu) binaries on this host. root@vps1724252356:~# sudo reboot Connection to 194.226.49.162 closed by remote host. Connection to 194.226.49.162 closed. 
Enter fullscreen mode Exit fullscreen mode

5. SSH key generation on a dedicated server

This is necessary so that we can download the repository to a dedicated server

Commands

ssh-keygen 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:SOME_RANDOM_SYMBOLS root@vps1724252356 The key's randomart image is: +---[RSA 3072]----+ | .o*oo. | +----[SHA256]-----+ 
Enter fullscreen mode Exit fullscreen mode

6. Linking a dedicated server's public key to GitHub

You need to run the command cat /root/.ssh/id_rsa.pub and paste the answer into the project settings, I have them here: https://github.com/nestjs-mod/nestjs-mod-fullstack/settings/keys/new

Commands

root@vps1724252356:~# cat /root/.ssh/id_rsa.pub 
Enter fullscreen mode Exit fullscreen mode

Console output
# cat /root/.ssh/id_rsa.pub ssh-rsa AAAARANDOM_SYMBOLS= root@vps1724252356 
Enter fullscreen mode Exit fullscreen mode

7. Cloning the project

Commands

git clone git@github.com:nestjs-mod/nestjs-mod-fullstack.git cd nestjs-mod-fullstack 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~# git clone git@github.com:nestjs-mod/nestjs-mod-fullstack.git Cloning into 'nestjs-mod-fullstack'... The authenticity of host 'github.com (140.82.121.3)' can't be established. ED25519 key fingerprint is SHA256:+SOME_RANDOM_SYMBOLS. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'github.com' (ED25519) to the list of known hosts. remote: Enumerating objects: 426, done. remote: Counting objects: 100% (426/426), done. remote: Compressing objects: 100% (294/294), done. remote: Total 426 (delta 190), reused 340 (delta 106), pack-reused 0 (from 0) Receiving objects: 100% (426/426), 536.69 KiB | 1.56 MiB/s, done. Resolving deltas: 100% (190/190), done. root@vps1724252356:~# cd nestjs-mod-fullstack root@vps1724252356:~/nestjs-mod-fullstack# 
Enter fullscreen mode Exit fullscreen mode

8. We install dependencies and run the launch and testing of two modes: PM2 production and Docker Compose

We run E2E tests by specifying the external global IP address of the applications.

Commands

npm i npx playwright install npx playwright install-deps npm run test cp example.env .env npm run pm2-full:prod:start export BASE_URL=http://194.226.49.162:3000 && npm run test:e2e npm run pm2-full:prod:stop npm run docker-compose-full:prod:start export BASE_URL=http://194.226.49.162:8080 && npm run test:e2e npm run docker-compose-full:prod:stop 
Enter fullscreen mode Exit fullscreen mode

E2E testing in the "Docker Compose" mode failed with an error, in the next steps we will fix them on the local computer and then through a commit to the project repository, we will deliver them to a dedicated server.

9. On the local computer, we update and add new npm scripts

During local development, a separately installed docker-compose application was used to run, and a dedicated server uses compose built into Docker.

We are deleting the script for copying the copy-front-to-backend statics, since now we go directly from the backend application to view the collected frontend statics.

To create databases and apply migrations, we created a separate npm script, since when trying to run two npm commands inside the container, only one was launched.

Updating the package.json

{ "scripts": { // ... "_____docker-compose-full prod infra_____": "_____docker-compose-full prod infra_____", "docker-compose-full:prod:start": "export NX_DAEMON=false && export DISABLE_SERVE_STATIC=true && npm run generate && npm run build -- -c production && npm run docker:build:server:latest && export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility up -d", "docker-compose-full:prod:stop": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility down", "docker-compose-full:prod:only-start": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility up -d", "docker-compose-full:prod:fill:database": "npm run db:create && npm run flyway:migrate", // ... "_____docker-compose prod-infra_____": "_____docker-compose prod-infra_____", "docker-compose:start-prod:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env --compatibility up -d", "docker-compose:stop-prod:server": "export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env down" } } 
Enter fullscreen mode Exit fullscreen mode

10. On the local computer, we update the parameters of the container with migrations in the "Docker Compose" file

Updated file .docker/docker-compose-full.yml

version: '3' networks: nestjs-mod-fullstack-network: driver: "bridge" services: nestjs-mod-fullstack-postgre-sql: image: 'bitnami/postgresql:15.5.0' container_name: 'nestjs-mod-fullstack-postgre-sql' networks: - 'nestjs-mod-fullstack-network' volumes: - 'nestjs-mod-fullstack-postgre-sql-volume:/bitnami/postgresql' healthcheck: test: - 'CMD-SHELL' - 'pg_isready -U postgres' interval: '5s' timeout: '5s' retries: 5 tty: true restart: 'always' environment: POSTGRESQL_USERNAME: '${SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME}' POSTGRESQL_PASSWORD: '${SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD}' POSTGRESQL_DATABASE: '${SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE}' nestjs-mod-fullstack-postgre-sql-migrations: image: 'node:20-bullseye-slim' container_name: 'nestjs-mod-fullstack-postgre-sql-migrations' networks: - 'nestjs-mod-fullstack-network' working_dir: '/app' volumes: - './../:/app' command: 'npm run docker-compose-full:prod:fill:database' tty: true environment: NX_SKIP_NX_CACHE: 'true' SERVER_ROOT_DATABASE_URL: '${SERVER_ROOT_DATABASE_URL}' SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}' depends_on: nestjs-mod-fullstack-postgre-sql: condition: 'service_healthy' nestjs-mod-fullstack-server: image: 'nestjs-mod-fullstack-server:latest' container_name: 'nestjs-mod-fullstack-server' networks: - 'nestjs-mod-fullstack-network' healthcheck: test: [ 'CMD-SHELL', 'npx -y wait-on --timeout= --interval=1000 --window --verbose --log http://localhost:8080/api/health', ] interval: 30s timeout: 10s retries: 10 tty: true environment: SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}' restart: 'always' depends_on: nestjs-mod-fullstack-postgre-sql: condition: service_healthy nestjs-mod-fullstack-postgre-sql-migrations: condition: service_completed_successfully nestjs-mod-fullstack-nginx: image: nginx:alpine container_name: 'nestjs-mod-fullstack-nginx' networks: - 'nestjs-mod-fullstack-network' volumes: - ../.docker/nginx:/etc/nginx/conf.d - ../dist/apps/client/browser:/usr/share/nginx/html restart: 'always' depends_on: nestjs-mod-fullstack-server: condition: service_healthy ports: - '8080:8080' nestjs-mod-fullstack-https-portal: image: steveltn/https-portal:1 container_name: 'nestjs-mod-fullstack-https-portal' networks: - 'nestjs-mod-fullstack-network' ports: - '80:80' - '443:443' links: - nestjs-mod-fullstack-nginx restart: always environment: STAGE: '${HTTPS_PORTAL_STAGE}' FORCE_RENEW: 'true' DOMAINS: '${SERVER_DOMAIN} -> http://nestjs-mod-fullstack-nginx:8080' depends_on: nestjs-mod-fullstack-nginx: condition: service_started volumes: - nestjs-mod-fullstack-https-portal-volume:/var/lib/https-portal volumes: nestjs-mod-fullstack-postgre-sql-volume: name: 'nestjs-mod-fullstack-postgre-sql-volume' nestjs-mod-fullstack-https-portal-volume: name: 'nestjs-mod-fullstack-https-portal-volume' 
Enter fullscreen mode Exit fullscreen mode

11. On the local computer, we open access to the Swagger interface of the backend in Nginx

Updated file .docker/nginx/nginx.conf

map $sent_http_content_type $expires { "text/html" epoch; "text/html; charset=utf-8" epoch; default off; } map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 8080; server_name localhost; gzip on; gzip_proxied any; gzip_types text/plain application/xml text/css application/javascript application/json; gzip_min_length 1000; gzip_vary on; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; client_max_body_size 50m; proxy_connect_timeout 5m; proxy_send_timeout 5m; proxy_read_timeout 5m; send_timeout 5m; proxy_max_temp_file_size 0; root /usr/share/nginx/html; index index.html; location /api { proxy_pass http://nestjs-mod-fullstack-server:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header Origin $http_origin; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # kill cache add_header Last-Modified $date_gmt; add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; etag off; } location /swagger { proxy_pass http://nestjs-mod-fullstack-server:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header Origin $http_origin; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # kill cache add_header Last-Modified $date_gmt; add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; etag off; } location / { expires $expires; proxy_redirect off; proxy_set_header Host $host; proxy_set_header Origin $http_origin; 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_read_timeout 1m; proxy_connect_timeout 1m; proxy_intercept_errors on; error_page 404 =200 /index.html; root /usr/share/nginx/html; } } 
Enter fullscreen mode Exit fullscreen mode

12. On the local computer, we add the ability to disable the NestJS module for static output

Since in the "Docker Compose" mode we distribute statics via Nginx, we do not need to build a backend with built-in statics and therefore do not need additional handlers to support static output.

Updated file apps/server/src/app/app.module.ts

import { createNestModule, NestModuleCategory } from '@nestjs-mod/common'; import { PrismaModule } from '@nestjs-mod/prisma'; import { ServeStaticModule } from '@nestjs/serve-static'; import { join } from 'path'; import { AppController } from './app.controller'; import { AppService } from './app.service'; export const { AppModule } = createNestModule({ moduleName: 'AppModule', moduleCategory: NestModuleCategory.feature, imports: [ PrismaModule.forFeature({ featureModuleName: 'app' }), ...(process.env.DISABLE_SERVE_STATIC ? [] : [ ServeStaticModule.forRoot({ rootPath: join(__dirname, 'assets', 'client'), }), ]), ], controllers: [AppController], providers: [AppService], }); 
Enter fullscreen mode Exit fullscreen mode

13. On the local computer, we run the launch and testing of two modes again: PM2 production and Docker Compose

We run E2E tests by specifying the external global IP address of the applications.

Commands

npm i npx playwright install npx playwright install-deps npm run test cp example.env .env npm run pm2-full:prod:start export BASE_URL=http://194.226.49.162:3000 && npm run test:e2e npm run pm2-full:prod:stop npm run docker-compose-full:prod:start export BASE_URL=http://194.226.49.162:8080 && npm run test:e2e npm run docker-compose-full:prod:stop 
Enter fullscreen mode Exit fullscreen mode

The tests were passed successfully

14. On the local computer, add an additional container with https-portal to docker-compose-full.yml for proxying http to https and adding the restart: 'always' option to all (except migrations) containers

Updated file .docker/docker-compose-full.yml

version: '3' networks: nestjs-mod-fullstack-network: driver: 'bridge' services: nestjs-mod-fullstack-postgre-sql: image: 'bitnami/postgresql:15.5.0' container_name: 'nestjs-mod-fullstack-postgre-sql' networks: - 'nestjs-mod-fullstack-network' volumes: - 'nestjs-mod-fullstack-postgre-sql-volume:/bitnami/postgresql' healthcheck: test: - 'CMD-SHELL' - 'pg_isready -U postgres' interval: '5s' timeout: '5s' retries: 5 tty: true restart: 'always' environment: POSTGRESQL_USERNAME: '${SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME}' POSTGRESQL_PASSWORD: '${SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD}' POSTGRESQL_DATABASE: '${SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE}' nestjs-mod-fullstack-postgre-sql-migrations: image: 'node:20-bullseye-slim' container_name: 'nestjs-mod-fullstack-postgre-sql-migrations' networks: - 'nestjs-mod-fullstack-network' working_dir: '/app' volumes: - './../:/app' command: 'npm run docker-compose-full:prod:fill:database' tty: true environment: NX_SKIP_NX_CACHE: 'true' SERVER_ROOT_DATABASE_URL: '${SERVER_ROOT_DATABASE_URL}' SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}' depends_on: nestjs-mod-fullstack-postgre-sql: condition: 'service_healthy' nestjs-mod-fullstack-server: image: 'nestjs-mod-fullstack-server:latest' container_name: 'nestjs-mod-fullstack-server' networks: - 'nestjs-mod-fullstack-network' healthcheck: test: ['CMD-SHELL', 'npx -y wait-on --timeout= --interval=1000 --window --verbose --log http://localhost:8080/api/health'] interval: 30s timeout: 10s retries: 10 tty: true environment: SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}' restart: 'always' depends_on: nestjs-mod-fullstack-postgre-sql: condition: service_healthy nestjs-mod-fullstack-postgre-sql-migrations: condition: service_completed_successfully nestjs-mod-fullstack-nginx: image: nginx:alpine container_name: 'nestjs-mod-fullstack-nginx' networks: - 'nestjs-mod-fullstack-network' volumes: - ../.docker/nginx:/etc/nginx/conf.d - ../dist/apps/client/browser:/usr/share/nginx/html restart: 'always' depends_on: nestjs-mod-fullstack-server: condition: service_healthy ports: - '8080:8080' nestjs-mod-fullstack-https-portal: image: steveltn/https-portal:1 container_name: 'nestjs-mod-fullstack-https-portal' networks: - 'nestjs-mod-fullstack-network' ports: - '80:80' - '443:443' links: - nestjs-mod-fullstack-nginx restart: always environment: STAGE: '${HTTPS_PORTAL_STAGE}' FORCE_RENEW: 'true' DOMAINS: '${SERVER_DOMAIN} -> http://nestjs-mod-fullstack-nginx:8080' depends_on: nestjs-mod-fullstack-nginx: condition: service_started volumes: - nestjs-mod-fullstack-https-portal-volume:/var/lib/https-portal volumes: nestjs-mod-fullstack-postgre-sql-volume: name: 'nestjs-mod-fullstack-postgre-sql-volume' nestjs-mod-fullstack-https-portal-volume: name: 'nestjs-mod-fullstack-https-portal-volume' 
Enter fullscreen mode Exit fullscreen mode

15. On the local computer, we add a new environment variable with our domain vps1724252356.tech0.ru

Updated file .docker/docker-compose-full.env

SERVER_ROOT_DATABASE_URL=postgres://postgres:postgres_password@nestjs-mod-fullstack-postgre-sql:5432/postgres?schema=public SERVER_APP_DATABASE_URL=postgres://app:app_password@nestjs-mod-fullstack-postgre-sql:5432/app?schema=public SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME=postgres SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD=postgres_password SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE=postgres SERVER_DOMAIN=vps1724252356.tech0.ru HTTPS_PORTAL_STAGE=production # local|production 
Enter fullscreen mode Exit fullscreen mode

16. On the local computer, commit the changes to the repository

Commands

git commit -m "fix: some updates" git push 
Enter fullscreen mode Exit fullscreen mode

17. We connect to the remote server, get new changes and stop the "PM2" and "Docker Compose" modes

Commands

ssh root@194.226.49.162 cd nestjs-mod-fullstack npm run pm2-full:prod:stop npm run docker-compose-full:prod:stop 
Enter fullscreen mode Exit fullscreen mode

18. Restart all applications in the "Docker Compose" mode and run E2E tests, specify the server address https://vps1724252356.tech0.ru

Commands

npm run docker-compose-full:prod:start export BASE_URL=https://vps1724252356.tech0.ru && npm run test:e2e 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~/nestjs-mod-fullstack# npm run docker-compose-full:prod:start > @nestjs-mod-fullstack/source@0.0.0 docker-compose-full:prod:start > export NX_DAEMON=false && export DISABLE_SERVE_STATIC=true && npm run generate && npm run build -- -c production && npm run docker:build:server:latest && export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./.docker/docker-compose-full.yml --env-file ./.docker/docker-compose-full.env --compatibility up -d > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix ✔ nx run server:generate (42s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target generate for project server (42s) > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-angular-rest-sdk:lint [existing outputs match the cache, left as is] ✔ nx run server:lint [existing outputs match the cache, left as is] ✔ nx run client:lint [existing outputs match the cache, left as is] ✔ nx run server-e2e:lint [existing outputs match the cache, left as is] —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target lint for 4 projects (357ms) With additional flags: --fix=true Nx read the output from the cache instead of running the command for 4 out of 4 tasks. > @nestjs-mod-fullstack/source@0.0.0 build > npm run generate && npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=build --skip-nx-cache=true -c production > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix ✔ nx run server:generate (38s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target generate for project server (38s) > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-angular-rest-sdk:lint [existing outputs match the cache, left as is] ✔ nx run server:lint [existing outputs match the cache, left as is] ✔ nx run client:lint [existing outputs match the cache, left as is] ✔ nx run server-e2e:lint [existing outputs match the cache, left as is] —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target lint for 4 projects (350ms) With additional flags: --fix=true Nx read the output from the cache instead of running the command for 4 out of 4 tasks. > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-rest-sdk:build (8s) ✔ nx run app-angular-rest-sdk:build:production (9s) ✔ nx run server:build:production (13s) ✔ nx run client:build:production (19s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target build for 4 projects (28s) > @nestjs-mod-fullstack/source@0.0.0 docker:build:server:latest > docker build -t nestjs-mod-fullstack-server:latest -f ./.docker/server.Dockerfile . --progress=plain #0 building with "default" instance using docker driver #1 [internal] load build definition from server.Dockerfile #1 transferring dockerfile: 1.65kB done #1 DONE 0.0s #2 [internal] load metadata for docker.io/library/node:20.16.0-alpine #2 DONE 1.2s #3 [internal] load .dockerignore #3 transferring context: 79B 0.0s done #3 DONE 0.0s #4 [builder 1/7] FROM docker.io/library/node:20.16.0-alpine@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 #4 DONE 0.0s #5 [internal] load build context #5 transferring context: 1.20MB 0.2s done #5 DONE 0.2s #6 [builder 2/7] WORKDIR /usr/src/app #6 CACHED #7 [builder 3/7] COPY . . #7 DONE 0.2s #8 [builder 4/7] RUN apk add dumb-init #8 0.630 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz #8 1.055 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz #8 1.791 (1/1) Installing dumb-init (1.2.5-r3) #8 1.820 Executing busybox-1.36.1-r29.trigger #8 1.836 OK: 11 MiB in 17 packages #8 DONE 2.0s #9 [builder 5/7] RUN apk add jq #9 1.136 (1/2) Installing oniguruma (6.9.9-r0) #9 1.302 (2/2) Installing jq (1.7.1-r0) #9 1.361 Executing busybox-1.36.1-r29.trigger #9 1.379 OK: 12 MiB in 19 packages #9 DONE 1.7s #10 [builder 6/7] RUN echo $(cat package.json | jq 'del(.devDependencies)') > package.json #10 DONE 0.5s #11 [builder 7/7] RUN rm -rf nx.json package-lock.json .dockerignore && cp .docker/nx.json nx.json && cp .docker/.dockerignore .dockerignore && npm install && npm install --save-dev nx@19.5.3 prisma@5.18.0 prisma-class-generator@0.2.11 && echo '' > .env && npm run prisma:generate && rm -rf /usr/src/app/node_modules/@nx && rm -rf /usr/src/app/node_modules/@prisma-class-generator && rm -rf /usr/src/app/node_modules/@angular && rm -rf /usr/src/app/node_modules/@swc && rm -rf /usr/src/app/node_modules/@babel && rm -rf /usr/src/app/node_modules/@angular-devkit && rm -rf /usr/src/app/node_modules/@ngneat && rm -rf /usr/src/app/node_modules/@types && rm -rf /usr/src/app/node_modules/@ng-packagr #11 112.9 #11 112.9 added 408 packages, and audited 409 packages in 2m #11 112.9 #11 112.9 53 packages are looking for funding #11 112.9 run `npm fund` for details #11 112.9 #11 112.9 5 moderate severity vulnerabilities #11 112.9 #11 112.9 To address all issues (including breaking changes), run: #11 112.9 npm audit fix --force #11 112.9 #11 112.9 Run `npm audit` for details. #11 112.9 npm notice #11 112.9 npm notice New patch version of npm available! 10.8.1 -> 10.8.2 #11 112.9 npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2 #11 112.9 npm notice To update run: npm install -g npm@10.8.2 #11 112.9 npm notice #11 166.3 #11 166.3 added 106 packages, and audited 515 packages in 53s #11 166.3 #11 166.3 66 packages are looking for funding #11 166.3 run `npm fund` for details #11 166.4 #11 166.4 5 moderate severity vulnerabilities #11 166.4 #11 166.4 To address all issues (including breaking changes), run: #11 166.4 npm audit fix --force #11 166.4 #11 166.4 Run `npm audit` for details. #11 166.7 #11 166.7 > @nestjs-mod-fullstack/source@0.0.0 prisma:generate #11 166.7 > ./node_modules/.bin/nx run-many -t=prisma-generate #11 166.7 #11 169.4 #11 169.4 NX Running target prisma-generate for project server: #11 169.4 #11 169.4 - server #11 169.4 #11 169.4 #11 177.6 #11 177.6 > nx run server:prisma-generate #11 177.6 #11 177.6 > ./node_modules/.bin/prisma generate --schema=./apps/server/src/prisma/app-schema.prisma #11 177.6 #11 177.6 Environment variables loaded from .env #11 177.6 Prisma schema loaded from apps/server/src/prisma/app-schema.prisma #11 177.6 prisma:info [Prisma Class Generator]:Handler Registered. #11 177.6 prisma:info [Prisma Class Generator]:Generate /usr/src/app/apps/server/src/app/generated/rest/dto/app_demo.ts #11 177.6 prisma:info [Prisma Class Generator]:Generate /usr/src/app/apps/server/src/app/generated/rest/dto/migrations.ts #11 177.6 #11 177.6 ✔ Generated Prisma Client (v5.18.0, engine=binary) to ./node_modules/@prisma/app-client in 308ms #11 177.6 #11 177.6 ✔ Generated Prisma Class Generator to ./apps/server/src/app/generated/rest/dto in 408ms #11 177.6 #11 177.6 Start by importing your Prisma Client (See: http://pris.ly/d/importing-client) #11 177.6 #11 177.6 Tip: Easily identify and fix slow SQL queries in your app. Optimize helps you enhance your visibility: https://pris.ly/--optimize #11 177.6 #11 177.6 #11 177.6 #11 177.6 #11 177.6 NX Successfully ran target prisma-generate for project server #11 177.6 #11 177.6 #11 DONE 178.9s #12 [stage-1 3/4] COPY --from=builder /usr/src/app/ /usr/src/app/ #12 DONE 8.3s #13 [stage-1 4/4] COPY --from=builder /usr/bin/dumb-init /usr/bin/dumb-init #13 DONE 0.1s #14 exporting to image #14 exporting layers #14 exporting layers 8.7s done #14 writing image sha256:049c6f471ddfe18b811e6aac12cccd777dfab0bb1d599b00c91beb51d1ff188f done #14 naming to docker.io/library/nestjs-mod-fullstack-server:latest done #14 DONE 8.7s WARN[0000] /root/nestjs-mod-fullstack/.docker/docker-compose-full.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion [+] Running 5/5 ✔ Container nestjs-mod-fullstack-postgre-sql Healthy 13.9s ✔ Container nestjs-mod-fullstack-postgre-sql-migrations Exited 30.9s ✔ Container nestjs-mod-fullstack-server Healthy 65.1s ✔ Container nestjs-mod-fullstack-nginx Started 65.1s ✔ Container nestjs-mod-fullstack-https-portal Started 65.2s root@vps1724252356:~/nestjs-mod-fullstack# export BASE_URL=https://vps1724252356.tech0.ru && npm run test:e2e > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes > nx run client-e2e:e2e > playwright test NX Running target e2e for 2 projects and 1 task they depend on NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/3 remaining tasks... ✔ nx run client-e2e:e2e (25s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✔ nx run server:build:production (14s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/1 remaining tasks... ⠹ nx run server-e2e:e2e ✔ 2/2 succeeded [0 read from cache] PASS server-e2e apps/server-e2e/src/server/server.spec.ts GET /api ✓ should return a message (160 ms) ✔ nx run server-e2e:e2e (10s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target e2e for 2 projects and 1 task they depend on (50s) 
Enter fullscreen mode Exit fullscreen mode

19. Restart all applications in PM2 production mode and run E2E tests, specify the server address http://vps1724252356.tech0.ru:3000

Commands

npm run pm2-full:prod:start export BASE_URL=http://vps1724252356.tech0.ru:3000 && npm run test:e2e 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~/nestjs-mod-fullstack# npm run pm2-full:prod:start > @nestjs-mod-fullstack/source@0.0.0 pm2-full:prod:start > npm run generate && npm run build -- -c production && npm run docker-compose:start-prod:server && npm run db:create && npm run flyway:migrate && npm run pm2:start > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix ✔ nx run server:generate (1m) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target generate for project server (1m) > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-angular-rest-sdk:lint [existing outputs match the cache, left as is] ✔ nx run client:lint [existing outputs match the cache, left as is] ✔ nx run server-e2e:lint [existing outputs match the cache, left as is] ✔ nx run server:lint (4s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target lint for 4 projects (5s) With additional flags: --fix=true Nx read the output from the cache instead of running the command for 3 out of 4 tasks. > @nestjs-mod-fullstack/source@0.0.0 build > npm run generate && npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=build --skip-nx-cache=true -c production > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix ✔ nx run server:generate (43s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target generate for project server (43s) > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-angular-rest-sdk:lint [existing outputs match the cache, left as is] ✔ nx run client:lint [existing outputs match the cache, left as is] ✔ nx run server:lint [existing outputs match the cache, left as is] ✔ nx run server-e2e:lint [existing outputs match the cache, left as is] —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target lint for 4 projects (373ms) With additional flags: --fix=true Nx read the output from the cache instead of running the command for 4 out of 4 tasks. > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run app-rest-sdk:build (1m) ✔ nx run app-angular-rest-sdk:build:production (1m) ✔ nx run server:build:production (1m) ✔ nx run client:build:production (23s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target build for 4 projects (2m) > @nestjs-mod-fullstack/source@0.0.0 docker-compose:start-prod:server > export COMPOSE_INTERACTIVE_NO_CLI=1 && docker compose -f ./apps/server/docker-compose-prod.yml --env-file ./apps/server/docker-compose-prod.env --compatibility up -d WARN[0000] /root/nestjs-mod-fullstack/apps/server/docker-compose-prod.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion [+] Running 1/1 ✔ Container server-postgre-sql Started 0.7s > @nestjs-mod-fullstack/source@0.0.0 db:create > ./node_modules/.bin/nx run-many -t=db-create ✔ nx run server:db-create (3s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target db-create for project server (4s) > @nestjs-mod-fullstack/source@0.0.0 flyway:migrate > ./node_modules/.bin/nx run-many -t=flyway-migrate ✔ nx run server:flyway-migrate (5s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target flyway-migrate for project server (5s) > @nestjs-mod-fullstack/source@0.0.0 pm2:start > ./node_modules/.bin/pm2 start ./ecosystem-prod.config.json && npm run wait-on -- --log http://localhost:3000/api/health --log http://localhost:3000 [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2 [PM2] PM2 Successfully daemonized [PM2][WARN] Applications nestjs-mod-fullstack not running, starting... [PM2] App [nestjs-mod-fullstack] launched (1 instances) ┌────┬─────────────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├────┼─────────────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ nestjs-mod-fullstack │ default │ N/A │ fork │ 505154 │ 0s │ 0 │ online │ 0% │ 28.8mb │ root │ disabled │ └────┴─────────────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘ > @nestjs-mod-fullstack/source@0.0.0 wait-on > ./node_modules/.bin/wait-on --timeout=240000 --interval=1000 --window --verbose --log http://localhost:3000/api/health --log http://localhost:3000 waiting for 2 resources: http://localhost:3000/api/health, http://localhost:3000 making HTTP(S) head request to url:http://localhost:3000/api/health ... making HTTP(S) head request to url:http://localhost:3000 ... HTTP(S) error for http://localhost:3000/api/health AggregateError HTTP(S) error for http://localhost:3000 AggregateError making HTTP(S) head request to url:http://localhost:3000/api/health ... making HTTP(S) head request to url:http://localhost:3000 ... HTTP(S) error for http://localhost:3000/api/health AggregateError HTTP(S) error for http://localhost:3000 AggregateError making HTTP(S) head request to url:http://localhost:3000/api/health ... HTTP(S) error for http://localhost:3000/api/health AggregateError making HTTP(S) head request to url:http://localhost:3000 ... HTTP(S) error for http://localhost:3000 AggregateError making HTTP(S) head request to url:http://localhost:3000/api/health ... making HTTP(S) head request to url:http://localhost:3000 ... HTTP(S) result for http://localhost:3000/api/health: { status: 200, statusText: 'OK', headers: Object [AxiosHeaders] { 'x-powered-by': 'Express', vary: 'Origin', 'access-control-allow-credentials': 'true', 'x-request-id': 'bd416d0d-2e53-4f4a-8402-58e367c833c5', 'cache-control': 'no-cache, no-store, must-revalidate', 'content-type': 'application/json; charset=utf-8', 'content-length': '107', etag: 'W/"6b-ouXVoNOXyOxnMfI7caewF8/p97A"', date: 'Thu, 22 Aug 2024 18:58:09 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, data: '' } waiting for 1 resources: http://localhost:3000 HTTP(S) result for http://localhost:3000: { status: 200, statusText: 'OK', headers: Object [AxiosHeaders] { 'x-powered-by': 'Express', vary: 'Origin', 'access-control-allow-credentials': 'true', 'accept-ranges': 'bytes', 'cache-control': 'public, max-age=0', 'last-modified': 'Thu, 22 Aug 2024 18:57:47 GMT', etag: 'W/"8e8-1917b73ba3d"', 'content-type': 'text/html; charset=UTF-8', 'content-length': '2280', date: 'Thu, 22 Aug 2024 18:58:09 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, data: '' } wait-on(505210) complete root@vps1724252356:~/nestjs-mod-fullstack# export BASE_URL=http://vps1724252356.tech0.ru:3000 && npm run test:e2e > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes > nx run client-e2e:e2e > playwright test NX Running target e2e for 2 projects and 1 task they depend on NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/3 remaining tasks... ✔ nx run client-e2e:e2e (39s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✔ nx run server:build:production (16s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/1 remaining tasks... ⠴ nx run server-e2e:e2e ✔ 2/2 succeeded [0 read from cache] PASS server-e2e apps/server-e2e/src/server/server.spec.ts GET /api ✓ should return a message (74 ms) ✔ nx run server-e2e:e2e (11s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target e2e for 2 projects and 1 task they depend on (1m) 
Enter fullscreen mode Exit fullscreen mode

20. Setting up the automatic restart of PM2 production mode when restarting the dedicated server

Commands

./node_modules/.bin/pm2 startup ./node_modules/.bin/pm2 save 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~/nestjs-mod-fullstack# ./node_modules/.bin/pm2 startup [PM2] Init System found: systemd Platform systemd Template [Unit] Description=PM2 process manager Documentation=https://pm2.keymetrics.io/ After=network.target [Service] Type=forking User=root LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity Environment=PATH=/root/.vscode-server/cli/servers/Stable-fee1edb8d6d72a0ddff41e5f71a671c23ed924b9/server/bin/remote-cli:/root/.nvm/versions/node/v20.16.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin Environment=PM2_HOME=/root/.pm2 PIDFile=/root/.pm2/pm2.pid Restart=on-failure ExecStart=/root/nestjs-mod-fullstack/node_modules/pm2/bin/pm2 resurrect ExecReload=/root/nestjs-mod-fullstack/node_modules/pm2/bin/pm2 reload all ExecStop=/root/nestjs-mod-fullstack/node_modules/pm2/bin/pm2 kill [Install] WantedBy=multi-user.target Target path /etc/systemd/system/pm2-root.service Command list [ 'systemctl enable pm2-root' ] [PM2] Writing init configuration in /etc/systemd/system/pm2-root.service [PM2] Making script booting at startup... [PM2] [-] Executing: systemctl enable pm2-root... Created symlink /etc/systemd/system/multi-user.target.wants/pm2-root.service → /etc/systemd/system/pm2-root.service. [PM2] [v] Command successfully executed. +---------------------------------------+ [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd root@vps1724252356:~/nestjs-mod-fullstack# ./node_modules/.bin/pm2 save [PM2] Saving current process list... [PM2] Successfully saved in /root/.pm2/dump.pm2 
Enter fullscreen mode Exit fullscreen mode

21. We reboot and check through the E2E test the operation of both modes

Commands

sudo reboot cd nestjs-mod-fullstack export BASE_URL=http://vps1724252356.tech0.ru:3000 && npm run test:e2e export BASE_URL=https://vps1724252356.tech0.ru && npm run test:e2e 
Enter fullscreen mode Exit fullscreen mode

Console output
root@vps1724252356:~/nestjs-mod-fullstack# export BASE_URL=http://vps1724252356.tech0.ru:3000 && npm run test:e2e > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes > nx run client-e2e:e2e > playwright test NX Running target e2e for 2 projects and 1 task they depend on NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/3 remaining tasks... ✔ nx run client-e2e:e2e (29s) ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✔ nx run server:build:production (15s) ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/1 remaining tasks... ⠏ nx run server-e2e:e2e ✔ 2/2 succeeded [0 read from cache] PASS server-e2e apps/server-e2e/src/server/server.spec.ts GET /api ✓ should return a message (73 ms) ✔ nx run server-e2e:e2e (12s) ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target e2e for 2 projects and 1 task they depend on (56s) 
Enter fullscreen mode Exit fullscreen mode

In the next post, I will add the CI/CD config for deployment to a dedicated server using GitHub Actions...

Links

https://nestjs.com - the official website of the framework
https://nestjs-mod.com - the official website of additional utilities
https://github.com/nestjs-mod/nestjs-mod-fullstack - the project from the post
https://github.com/nestjs-mod/nestjs-mod-fullstack/commit/b9715a203364877a4ffae6e7cb3a1dff59ede6d6 - commit to current changes

Top comments (0)