 Autor: [Adam Nadolny](/autorzy/adam-nadolny) Ekspert DevOps i infrastruktury · Zweryfikowano Kwiecień 2026

1.  [Strona główna](/) ›
2.  [Baza wiedzy](/baza-wiedzy/) ›
3.  NestJS — deployment na VPS

# NestJS — deployment aplikacji Node.js na VPS z PM2

Opublikowano: 10 kwietnia 2026 · Kategoria: VPS

NestJS to opinionated framework Node.js zbudowany nad Express (lub Fastify) z TypeScriptem, modułami, dependency injection i dekoratorami w stylu Angular. Sprawdza się świetnie przy większych API, mikrousługach i teamach — wymusza spójną strukturę tam, gdzie Express pozwala na dowolność. Deployment na VPS składa się z: build produkcyjny, PM2 cluster mode dla wielordzeniowych CPU, Nginx reverse proxy z SSL i TypeORM podpiętym do PostgreSQL.

## Inicjalizacja projektu i struktura modułów

\# Instalacja NestJS CLI i stworzenie projektu
npm install -g @nestjs/cli
nest new my-api --package-manager npm
cd my-api

# Dodanie zaleznosci produkcyjnych
npm install @nestjs/config @nestjs/typeorm typeorm pg
npm install @nestjs/terminus   # health checks
npm install @nestjs/swagger swagger-ui-express  # dokumentacja API

# Wygenerowanie modulu, kontrolera i serwisu
nest generate module users
nest generate controller users
nest generate service users

# Struktura projektu (po generacji)
# src/
# ├── app.module.ts        # Glowny modul
# ├── main.ts              # Entry point (bootstrap)
# ├── users/
# │   ├── users.module.ts
# │   ├── users.controller.ts
# │   ├── users.service.ts
# │   ├── entities/user.entity.ts
# │   └── dto/
# │       ├── create-user.dto.ts
# │       └── update-user.dto.ts
# └── health/
#     └── health.module.ts

## Konfiguracja aplikacji — main.ts i AppModule

// main.ts — produkcyjny bootstrap
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: \['error', 'warn', 'log'\],
  });

  // Globalna walidacja DTO
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,       // ignoruj nieznane pola
    forbidNonWhitelisted: true,
    transform: true,       // auto-transform typow
  }));

  // CORS (dostosuj do swojej domeny frontendowej)
  app.enableCors({
    origin: process.env.FRONTEND\_URL ?? 'http://localhost:3000',
    credentials: true,
  });

  // Swagger tylko w dev
  if (process.env.NODE\_ENV !== 'production') {
    const config = new DocumentBuilder()
      .setTitle('Moje API')
      .setVersion('1.0')
      .addBearerAuth()
      .build();
    const document = SwaggerModule.createDocument(app, config);
    SwaggerModule.setup('docs', app, document);
  }

  const port = parseInt(process.env.PORT ?? '3000', 10);
  await app.listen(port, '127.0.0.1');  // sluchaj tylko na localhost — Nginx stoi przed
  console.log(\`Application running on port ${port}\`);
}
bootstrap();

// app.module.ts — konfiguracja globalnych modułow
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersModule } from './users/users.module';
import { HealthModule } from './health/health.module';

@Module({
  imports: \[
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    TypeOrmModule.forRootAsync({
      imports: \[ConfigModule\],
      useFactory: (config: ConfigService) => ({
        type: 'postgres',
        host: config.get('DB\_HOST', 'localhost'),
        port: config.get<number>('DB\_PORT', 5432),
        username: config.get('DB\_USER'),
        password: config.get('DB\_PASS'),
        database: config.get('DB\_NAME'),
        entities: \[\_\_dirname + '/\*\*/\*.entity{.ts,.js}'\],
        synchronize: false,  // NIGDY true w produkcji — uzyj migracji
        ssl: config.get('DB\_SSL') === 'true' ? { rejectUnauthorized: false } : false,
      }),
      inject: \[ConfigService\],
    }),
    UsersModule,
    HealthModule,
  \],
})
export class AppModule {}

## TypeORM — entity, DTO i serwis

// entities/user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  hashedPassword: string;

  @Column({ default: true })
  isActive: boolean;

  @CreateDateColumn()
  createdAt: Date;
}

// dto/create-user.dto.ts
import { IsEmail, IsString, MinLength } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  password: string;
}

// users/users.service.ts
import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import \* as bcrypt from 'bcrypt';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly usersRepository: Repository<User>,
  ) {}

  async create(dto: CreateUserDto): Promise<User> {
    const existing = await this.usersRepository.findOneBy({ email: dto.email });
    if (existing) throw new ConflictException('Email already registered');

    const hashedPassword = await bcrypt.hash(dto.password, 12);
    const user = this.usersRepository.create({ email: dto.email, hashedPassword });
    return this.usersRepository.save(user);
  }

  async findAll(): Promise<User\[\]> {
    return this.usersRepository.find({ where: { isActive: true } });
  }

  async findOne(id: number): Promise<User> {
    const user = await this.usersRepository.findOneBy({ id });
    if (!user) throw new NotFoundException(\`User #${id} not found\`);
    return user;
  }
}

## Build produkcyjny i PM2 cluster mode

\# Build produkcyjny (kompilacja TypeScript)
npm run build
# Wynik: katalog dist/ z plikami .js

# ecosystem.config.js dla PM2
module.exports = {
  apps: \[
    {
      name: 'nestjs-api',
      script: 'dist/main.js',
      instances: 'max',        // jeden proces per CPU
      exec\_mode: 'cluster',
      autorestart: true,
      watch: false,
      max\_memory\_restart: '512M',
      env\_production: {
        NODE\_ENV: 'production',
        PORT: 3000,
      },
      error\_file: '/var/log/nestjs/error.log',
      out\_file: '/var/log/nestjs/out.log',
      log\_date\_format: 'YYYY-MM-DD HH:mm:ss Z',
    },
  \],
};

# Start i autostart
pm2 start ecosystem.config.js --env production
pm2 save
pm2 startup   # wygeneruje komende do uruchomienia przy restarcie

# Zero-downtime reload (bez przerwy w dzialaniu)
pm2 reload nestjs-api

# Status i logi
pm2 status
pm2 logs nestjs-api --lines 50

# Monitorowanie w czasie rzeczywistym
pm2 monit

## Nginx reverse proxy dla NestJS

\# /etc/nginx/sites-available/nestjs-api
upstream nestjs\_backend {
    server 127.0.0.1:3000;
    keepalive 64;
}

server {
    listen 443 ssl http2;
    server\_name api.example.com;

    ssl\_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl\_certificate\_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl\_protocols TLSv1.2 TLSv1.3;
    ssl\_session\_cache shared:SSL:10m;

    location / {
        proxy\_pass http://nestjs\_backend;
        proxy\_http\_version 1.1;
        proxy\_set\_header Upgrade $http\_upgrade;
        proxy\_set\_header Connection 'upgrade';
        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\_cache\_bypass $http\_upgrade;
        proxy\_read\_timeout 60s;
    }

    # WebSockets (NestJS Gateway)
    location /socket.io/ {
        proxy\_pass http://nestjs\_backend;
        proxy\_http\_version 1.1;
        proxy\_set\_header Upgrade $http\_upgrade;
        proxy\_set\_header Connection "upgrade";
    }
}

## Health checks z @nestjs/terminus

// health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator,
         MemoryHealthIndicator } from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private db: TypeOrmHealthIndicator,
    private memory: MemoryHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check(\[
      () => this.db.pingCheck('database'),
      () => this.memory.checkHeap('memory\_heap', 512 \* 1024 \* 1024),  // 512 MB
    \]);
  }
}

// Przyklad odpowiedzi GET /health:
// {
//   "status": "ok",
//   "info": {
//     "database": { "status": "up" },
//     "memory\_heap": { "status": "up" }
//   }
// }

## NestJS vs Express — porównanie

Cecha

NestJS

Express

Struktura projektu

Narzucona (moduły, DI)

Dowolna (elastyczna)

TypeScript

First-class (natywny)

Opcjonalny (@types/express)

Dependency Injection

Wbudowany kontener

Brak (ręcznie lub biblioteka)

Walidacja

class-validator + Pipes

express-validator / joi

Dokumentacja API

@nestjs/swagger (auto)

swagger-jsdoc (ręcznie)

Mikrousługi

Wbudowane transporty

Osobne biblioteki

Krzywa nauki

Wyższa (dekoratory)

Niska

Kiedy wybrać

Duże projekty, teamy

Proste API, szybki prototyp

## Najczęstsze pytania

NestJS vs Express — który wybrać do nowego projektu? +

NestJS to opinionated framework zbudowany nad Express (domyślnie) lub Fastify. Daje strukturę modułów, dependency injection, dekoratory i TypeScript z natury. Express jest prostszy, ale wymaga własnej architektury. Dla małych API Express jest wystarczający. Dla większych projektów z teamem NestJS wymusza spójną strukturę i jest łatwiejszy w utrzymaniu. NestJS jest też świetny dla mikrousług — ma wbudowane transporty (gRPC, RabbitMQ, Kafka).

PM2 cluster mode vs fork mode — kiedy używać którego? +

Fork mode tworzy jeden proces Node.js (domyślnie). Cluster mode tworzy N procesów używając Node.js cluster module — wszystkie dzielą jeden port (OS round-robin). Cluster mode używaj gdy masz wiele rdzeni CPU i chcesz je wykorzystać (instances: "max"). Pamiętaj: cluster mode nie obsługuje współdzielonego stanu — użyj Redis dla sesji i cache. NestJS z Fastify adapter + PM2 cluster to silna kombinacja produkcyjna.

Jak skonfigurować zmienne środowiskowe w NestJS produkcyjnie? +

Używaj @nestjs/config (ConfigModule) z plikiem .env. W produkcji: ConfigModule.forRoot({ isGlobal: true, cache: true }). Nie importuj ConfigModule w każdym module — zrób go globalnym. Zmienne przekazuj do VPS przez systemd EnvironmentFile lub PM2 env w ecosystem.config.js. Nigdy nie commituj .env do git — używaj .env.example z pustymi wartościami.

Jak zrobić health check w NestJS? +

Użyj pakietu @nestjs/terminus. Instalacja: npm install @nestjs/terminus. Stwórz HealthModule z HealthController i HealthCheckService. Dodaj checkery: HttpHealthIndicator (zewnętrzne URL), TypeOrmHealthIndicator (baza), MemoryHealthIndicator. Endpoint GET /health zwraca status ok/error z detalami każdego checka w formacie JSON. Nginx i monitoringi (UptimeRobot) mogą pollować ten endpoint.

## Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.

Contabo

VPS pod NestJS — wiele rdzeni dla PM2 cluster mode

VPS + CPU

[Aktywuj rabat →](/out/contabo)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/contabo)

ProSerwer.pl

Polski VPS pod NestJS z wsparciem technicznym

Polski VPS

[Aktywuj rabat →](/out/proserwer-pl)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/proserwer)

Mikr.us

Budżetowy VPS do testów i mniejszych aplikacji NestJS

Dev/Test

[Aktywuj rabat →](/out/mikrus)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/mikrus)

## Powiązane strony

-   [Node.js Express — deployment na VPS w produkcji](/baza-wiedzy/nodejs-express-produkcja)
-   [PM2 — zarządzanie procesami Node.js na VPS](/baza-wiedzy/pm2-nodejs-vps)
-   [PostgreSQL na VPS — instalacja i konfiguracja](/baza-wiedzy/postgresql-vps-instalacja-konfiguracja)
-   [Wszystkie artykuły](/baza-wiedzy/)