Nasazení Node.js aplikací na server: hosting a kontejnery

Architektury nasazení a životní cyklus Node.js aplikace

Nasazení Node.js aplikací na server zahrnuje volbu architektury (single host, kontejnery, orchestrátor), způsob běhu procesu, reverzní proxy, škálování, observability a automatizace. Typický životní cyklus zahrnuje build (transpilaci/kompilaci TypeScriptu), přípravu prostředí (proměnné, tajemství), rollout (zero-downtime), monitoring a rollback. Správná volba cíle (VPS, bare metal, PaaS, Kubernetes) se řídí požadavky na SLA, propustnost, rozpočet a týmové dovednosti.

Volba runtime a správa verzí Node.js

  • LTS vs. Current – v produkci preferujte LTS kvůli stabilitě knihoven a bezpečnostním aktualizacím.
  • Správa verzí – nástroje nvm, fnm nebo asdf pro vývoj; v produkci fixujte verzi přes systémové balíčky, Dockerfile base image nebo binární distribuci (např. node:20-alpine).
  • ESM vs. CommonJS – sjednoťte modulový systém; pro ESM nastavte "type": "module" a sladěné bundlery.

Příprava aplikace: build, bundling a artefakty

  • TypeScript – transpilujte do dist/ a nasazujte pouze artefakty (nikoli node_modules z vývoje). Zvažte tsup/esbuild pro rychlý bundling.
  • Pruning závislostí – používejte npm ci --omit=dev nebo pnpm install --prod v CI pro minimalizaci obrazu či balíčku.
  • Determinizmus – commitujte package-lock.json/pnpm-lock.yaml a sledujte NODE_OPTIONS=--conditions=production dle potřeby.

Procesní model: systemd, PM2 a cluster

Node.js běží jako single-thread event loop. Pro využití vícejádrových procesorů použijte procesní model (více instancí) nebo cluster v kombinaci s procesovým manažerem.

  • systemd – standardní správce služeb na Linuxu; nabízí restart, logging (journald), watchdog a sandboxing.
  • PM2 – pohodlný procesový manažer s cluster mode, rotací logů a jednoduchým zero-downtime reload.
  • Node cluster – vytváří worker procesy sdílející port; preferujte jeho použití přes nástroj (PM2), který řeší životní cyklus.

Ukázka systemd jednotky:

[Unit]
Description=My Node.js API
After=network.target

[Service]
Environment=NODE_ENV=production
EnvironmentFile=/etc/myapi.env
WorkingDirectory=/srv/myapi
ExecStart=/usr/bin/node dist/server.js
Restart=always
RestartSec=3
User=node
Group=node
# Bezpečnostní omezení
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
AmbientCapabilities=

[Install]
WantedBy=multi-user.target

Reverzní proxy: Nginx / Caddy jako terminátor TLS a load balancer

Node server (např. Fastify/Express) typicky běží na interním portu (např. 3000). Reverzní proxy:

  • terminuje TLS (Let’s Encrypt),
  • zajišťuje bezpečnostní hlavičky (HSTS, CSP, CORS),
  • provádí rate limiting a kompresi,
  • balancuje zatížení mezi více instancemi (upstream pool).

Ukázka Nginx konfigurace:

upstream myapi {
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    keepalive 64;
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;
}

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;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;

    location / {
        proxy_pass http://myapi;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_read_timeout 60s;
    }
}

Dockerizace a immutable nasazení

Kontejnerové nasazení usnadňuje správu závislostí a zajišťuje reprodukovatelnost. Doporučení:

  • Multi-stage build – oddělte build a runtime image; používejte Alpine/Distroless pro malé obrazy.
  • Neprivilegovaný uživatel – nastavte USER node a používejte porty nad 1024 (např. 3000).
  • Healthcheck – definujte HTTP endpoint pro liveness/readiness.

Příklad Dockerfile:

# Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

# Runtime stage
FROM node:20-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY --from=build /app/package*.json ./
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://127.0.0.1:3000/health || exit 1
CMD ["node", "dist/server.js"]

CI/CD: build, test, audit a rollout

Pipeline by měla obsahovat:

  1. Linting/testy (unit, e2e), SCA (npm audit, osv), SAST.
  2. Build artefaktu (tarball/Docker image) a jeho podepsání (Sigstore/cosign).
  3. Deploy na staging, smoke testy, následně produkce (blue-green/canary).

Ukázka GitHub Actions (zkráceně):

name: ci
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run lint && npm test
      - run: npm run build
      - run: npm prune --omit=dev
      - name: Build image
        run: docker build -t ghcr.io/org/myapi:${{ github.sha }} .

Zero-downtime release: blue-green a canary

  • Blue-green – provozují se dvě identické verze (blue a green). Po validaci přepněte traffic (Nginx upstream, load balancer) a starou verzi ukončete.
  • Canary – nasadíte malému procentu uživatelů; sledujete metriky a postupně zvyšujete podíl.
  • PM2 reload – umožňuje plynulé přepnutí workerů bez výpadku (graceful restart).

Graceful shutdown a signal handling

Správná obsluha signálu SIGTERM zamezí přerušení zpracovávaných požadavků a poškození transakcí.

import http from 'node:http';
import { pool } from './db.js'; // příklad: pg/pool

const server = http.createServer(app);
const PORT = process.env.PORT ?? 3000;

server.listen(PORT, () => console.log(`Listening on ${PORT}`));

let shuttingDown = false;

process.on('SIGTERM', async () => {
  if (shuttingDown) return;
  shuttingDown = true;

  console.log('SIGTERM received. Starting graceful shutdown...');

  server.close(async () => {
    try {
      await pool.end(); // uzavřít DB pool
      console.log('Shutdown complete.');
      process.exit(0);
    } catch (e) {
      console.error('Error during shutdown', e);
      process.exit(1);
    }
  });

  // volitelně: po X sekundách vynutit exit
  setTimeout(() => process.exit(1), 10000).unref();
});

Konfigurace, tajemství a prostředí

  • 12-factor – konfiguraci držte v proměnných prostředí (DATABASE_URL, REDIS_URL atd.). Citlivá data nikdy neukládejte do repozitáře.
  • Secret management – OS úložiště (systemd EnvironmentFile s přístupovými právy), Vault, SOPS + KMS, Docker/Kubernetes Secrets.
  • Konfigurační validace – validační schéma při startu (např. Zod/TypeBox) a fail-fast chování.

Databáze a migrace schématu

Produkční nasazení vyžaduje bezpečný a bezvýpadkový postup migrací:

  • Bez výpadku – měňte schéma kompatibilně (přidání sloupců s defaultní hodnotou, backfill dat, následné přepnutí kódu).
  • Nástroje – Prisma Migrate, Knex, TypeORM, Flyway. Logujte verze migrací a zachovávejte idempotentnost.
  • Poolování – správně nastavte velikost poolu, timeouty a backoff (např. pg, mysql2).

Cache, CDN a výkon

  • HTTP cache – používejte ETag, Cache-Control, Vary. Reverzní proxy může cachovat idempotentní GET požadavky.
  • Aplikační cache – Redis/Memcached pro náročné dotazy; invalidace na změnu dat (eventy, TTL).
  • Profilaceclinic.js, 0x, node --prof; sledujte garbage collection, event loop lag a alokace paměti.

WebSockety, SSE a sticky sessions

Pro real-time aplikace je nezbytná správná konfigurace proxy a škálování:

  • Upgrade hlavičky – Nginx musí povolit Connection: upgrade a Upgrade: websocket.
  • Sticky routing – u WS často vyžadován; jinak sdílejte stav přes Redis (Socket.IO adapter) nebo použijte pub/sub mechanizmy.
  • SSE – jednodušší než WS, ale pozor na limity paralelních spojení a timeouts.

Observability: logování, metriky, trace

  • Strukturované logy – JSON formát (pino/winston), unikátní request-id, korelace přes X-Request-ID.
  • Metriky – Prometheus endpoint (p95 latence, error rate, throughput), scrapování a dashboardy (Grafana).
  • Tracing – OpenTelemetry pro distribuovaný tracing; export do Jaeger/Tempo/OTLP.
  • Alerting – SLO/SLI (např. 99,9 % dostupnosti), alerty na chyby a saturaci zdrojů.

Bezpečnost produkce

  • Závislosti – pravidelné aktualizace, audit, blokování známých CVE (npm audit-level), Dependabot.
  • HTTP hlavičkyHelmet (CSP, HSTS, ochrana proti XSS, no-sniff), omezení HTTP metod a velikostí payloadů.
  • Rate limiting – v proxy i aplikaci; ochrana proti brute-force a DoS útokům.
  • Secrets – nikdy neukládejte do logů; pravidelně rotujte klíče, používejte krátkodobé tokeny (OIDC).
  • Sandboxing – systemd omezení, seccomp v Dockeru, read-only filesystem, drop capabilities.

Škálování: vertikální, horizontální a Kubernetes

  • Vertikální – navyšování CPU/RAM; rychlé, ale limitované rozšíření.
  • Horizontální – více instancí za load balancerem; stateless design (session do Redis/DB, soubory do objektového úložiště).
  • Kubernetes – auto-healing, autoscaling (HPA), rolling updates; vyžaduje vyšší provozní zralost týmu.

PM2 ekosystém a zero-downtime reload

Příklad ecosystem.config.js:

module.exports = {
  apps: [{
    name: "myapi",
    script: "dist/server.js",
    instances: "max",
    exec_mode: "cluster",
    env: {
      NODE_ENV: "production"
    },
    watch: false,
    max_memory_restart: "512M"
  }]
};

Nasazení: pm2 start ecosystem.config.js, rollout: pm2 reload myapi pro plynulý restart workerů bez výpadku.

Migrace bez výpadku a řízení verzí API

  • Zpětná kompatibilita – nasazujte kód, který podporuje stará i nová pole. Teprve poté proveďte nepřímé změny v databázi s »breaking« charakterem.
  • Verzování API – použijte namespace jako /v1, /v2 nebo content negotiation; dokumentujte pomocí OpenAPI.

Zálohy, obnova a disaster recovery

  • Runbooky – dokumentované postupy pro incidenty, rollback a obnovu.
  • Zálohy – pravidelné snapshoty databází a objektových storage, ověřování obnovy („fire drill“).
  • Multi-region – pro kritické služby replikace dat a failover provozu mezi regiony.

Řízení nákladů a efektivita

  • Profilování – identifikujte výkonové úzká místa dříve, než navýšíte klastr.
  • Autoscaling a plánování – přizpůsobte kapacitu