HostiServer
2026-03-23 12:40:00
Node.js na VPS: kompletní průvodce od instalace po production v roce 2026
Proč Node.js na VPS — a proč ne sdílený hosting
Problém je v tom, že většina návodů na internetu končí u node app.js — a to je vše, jako by aplikace byla připravená na production. Ve skutečnosti je mezi „spustil jsem na localhost" a „aplikace stabilně běží pod zátěží" obrovská propast: správce procesů, reverse proxy, SSL, firewall, monitoring, ochrana před úniky paměti.
V tomto průvodci — kompletní cesta od čistého Ubuntu serveru k production-ready Node.js. Každý krok s reálnými konfiguracemi a vysvětlením proč právě takto, a ne jinak. Veškerý materiál vychází z doporučení inženýrů Hostiserver, kteří s Node.js projekty klientů pracují každý den.
Krok 1: Příprava VPS
Před instalací Node.js — základní nastavení bezpečnosti. Zabere to 10 minut, ale ušetří vám problémy později. Čerstvý Ubuntu VPS bez těchto kroků je jako byt s otevřenými dveřmi: dříve či později někdo vejde.
Co se týče výběru konfigurace VPS: pro malé API nebo bota stačí 1 vCPU a 2 GB RAM. Pro středně velký projekt s PM2 Cluster Mode, Redis a Nginx — doporučujeme od 2 vCPU a 4 GB. NVMe disk je nezbytný pokud používáte Redis nebo máte intenzivní logování — rozdíl oproti HDD při náhodném čtení/zápisu je obrovský.
Aktualizace systému
První co na novém serveru uděláme — aktualizujeme balíčky. Stará verze OpenSSL nebo jádra znamená známé zranitelnosti, které využívají automatické skenery:
sudo apt update && sudo apt upgrade -y
Vytvoření samostatného uživatele
Nikdy nespouštějte Node.js jako root. Vytvořte samostatného uživatele s omezenými právy:
sudo adduser nodeapp
sudo usermod -aG sudo nodeapp
su - nodeapp
Nastavení firewallu (UFW)
Ubuntu má vestavěný UFW (Uncomplicated Firewall), ale ve výchozím stavu je vypnutý. Zapneme ho a otevřeme pouze tři porty — SSH pro správu, 80 pro HTTP a 443 pro HTTPS:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Po aktivaci zkontrolujte stav příkazem sudo ufw status — v seznamu by měla být pouze tato tři pravidla. Vše ostatní je automaticky blokováno.
⚠️ Důležité: Neotvírejte port 3000 (nebo jiný port aplikace) směrem ven. Nginx bude proxy provoz z 80/443 na vaši aplikaci. Přímý přístup k portu Node.js je bezpečnostní díra.
SSH klíče místo hesel — povinné. Heslem chráněné přihlašování je jednou z nejčastějších příčin průniku na servery přes brute-force. Pokud jste ještě nenastavili SSH klíče — udělejte to jako první, ještě před instalací Node.js. Vygenerujte pár klíčů na lokálním stroji (ssh-keygen -t ed25519), zkopírujte veřejný klíč na server (ssh-copy-id nodeapp@your-server-ip) a vypněte heslem chráněné přihlašování v /etc/ssh/sshd_config.
Krok 2: Instalace Node.js přes NVM
Zapomeňte na apt install nodejs — tento příkaz vám dá zastaralou verzi z repozitáře Ubuntu a vytvoří konflikty pokud na serveru běží více než jeden projekt. Problém není jen ve verzi: při aktualizaci přes apt se mohou rozbít globální npm balíčky a vrátit změny bez odstranění všeho je obtížné.
Správný způsob je NVM (Node Version Manager). Instaluje se do domovského adresáře uživatele, nepotřebuje sudo a umožňuje okamžité přepínání mezi verzemi pro různé projekty. Jeden VPS — dva projekty — jeden na Node 20, druhý na Node 22 — žádné konflikty.
Instalace NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
Instalace Node.js LTS
nvm install 22
nvm use 22
nvm alias default 22
V roce 2026 je zlatým standardem LTS 22.x. Tato verze poskytuje rovnováhu mezi novými funkcemi (aktualizovaný V8 engine, nativní Fetch API) a stabilitou pro production.
Ověření
node -v # v22.x.x
npm -v # 10.x.x
ℹ️ Alternativa: Fast Node Manager (fnm) — rychlejší alternativa k NVM, napsaná v Rustu. Obě varianty jsou vhodné pro production. Klíčové je — nepoužívejte systémový správce balíčků.
Krok 3: Nasazení aplikace
Server je připravený, Node.js nainstalovaný — čas nasadit samotnou aplikaci. Nejjednodušší způsob je přes Git. Pokud ještě nemáte repozitář — teď je ten správný čas ho vytvořit, protože nasazovat přes FTP nebo scp jednotlivé soubory v roce 2026 je cesta k chaosu s verzemi.
cd /home/nodeapp
git clone https://github.com/your-user/your-app.git
cd your-app
npm install --production
Příznak --production přeskočí devDependencies — testovací frameworky, lintery a build nástroje nejsou na production serveru potřeba. To šetří místo a snižuje počet potenciálních zranitelností.
Pokud máte na VPS více projektů — každý ve vlastním adresáři s vlastním ecosystem.config.js pro PM2 a samostatnou konfigurací Nginx. Například: /home/nodeapp/api na portu 3000 a /home/nodeapp/admin na portu 3001, každý za svým Nginx server blokem.
Soubor prostředí (.env)
Nikdy neukládejte hesla a klíče v kódu. Vytvořte soubor .env:
NODE_ENV=production
PORT=3000
DB_HOST=localhost
DB_PASSWORD=your_secure_password
SESSION_SECRET=random_string_here
🚨 Pozor: Přidejte .env do .gitignore. Pokud se tento soubor dostane do Git repozitáře — považujte všechna hesla za kompromitovaná.
Testovací spuštění
node app.js
Pokud se aplikace spustí bez chyb a odpovídá na curl http://localhost:3000 — přecházíme k PM2.
Krok 4: PM2 pro production
Spouštět Node.js přes node app.js v production je jako jízda bez bezpečnostního pásu. Proces spadne na první neošetřené chybě a nikdo ho nerestartuje.
PM2 je de facto standard pro správu Node.js procesů. Restartuje aplikaci při pádu, rozděluje zátěž mezi jádra a přežije restart serveru. Bez PM2 jakákoliv neošetřená výjimka zastaví váš proces — a obnovit ho může pouze administrátor ručně, pokud si problému všimne.
Instalace
npm install -g pm2
ecosystem.config.js
Místo spouštění z příkazové řádky — vytvořte konfigurační soubor:
module.exports = {
apps: [{
name: 'my-app',
script: './app.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '1G',
exp_backoff_restart_delay: 100,
env_production: {
NODE_ENV: 'production',
PORT: 3000
}
}]
};
Co je zde důležité:
- instances: 'max' — PM2 automaticky vytvoří jeden proces na každé jádro CPU. Na VPS se 4 jádry — 4 procesy, každý zpracovává požadavky paralelně.
- exec_mode: 'cluster' — povinné. Bez cluster režimu Node.js využívá pouze jedno jádro, ostatní se nevyužívají.
- max_memory_restart: '1G' — ochrana před úniky paměti. Pokud proces spotřebuje více než 1 GB — PM2 ho tiše restartuje bez výpadku (ostatní procesy pokračují v práci).
- exp_backoff_restart_delay — pokud aplikace padá cyklicky, prodleva mezi restarty se postupně zvyšuje. Bez toho by PM2 mohl vytvořit nekonečný cyklus restartů.
Spuštění a automatický start
pm2 start ecosystem.config.js --env production
pm2 save
pm2 startup
Nyní aplikace přežije restart serveru a spustí se automaticky.
Užitečné příkazy PM2
pm2 list # Seznam procesů
pm2 logs my-app # Logy v reálném čase
pm2 monit # Monitoring CPU/RAM
pm2 reload my-app # Zero-downtime restart
Krok 5: Nginx jako reverse proxy + SSL
Node.js by neměl poslouchat na portu 80 nebo 443 přímo. To je jedna z nejčastějších chyb — „proč potřebuji Nginx, když Node.js sám umí HTTP?" Odpověď: Nginx stojí před Node.js a zajišťuje úkoly, které Node.js dělá špatně nebo vůbec.
SSL terminace — Nginx zpracovává šifrování výrazně efektivněji. Ochrana před slow loris a dalšími pomalými útoky — Node.js by na každé takové spojení vynaložil celé vlákno event loop, Nginx ne. Statické soubory — Nginx je servíruje přímo z disku bez zatížení Node.js. Vyvažování zátěže — pokud PM2 spustil 4 workery, Nginx rozdělí požadavky mezi ně.
Instalace Nginx a Certbot
Nginx je nejpopulárnější reverse proxy pro Node.js. Certbot od Let's Encrypt vydává bezplatné SSL certifikáty s automatickou obnovou každých 90 dní:
sudo apt install nginx certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com
Certbot sám přidá SSL řádky do konfigurace Nginx. Ověřit že automatická obnova funguje můžete příkazem sudo certbot renew --dry-run.
Konfigurace Nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
# Podpora WebSockets
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_cache_bypass $http_upgrade;
# Timeouty
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
💡 Tip: Věnujte pozornost řádkům proxy_set_header Upgrade a Connection 'upgrade' — bez nich WebSocket spojení (chaty, notifikace, real-time dashboardy) přes Nginx nebudou fungovat.
Kontrola a restart
sudo nginx -t
sudo systemctl reload nginx
Nezapomeňte také přidat blok pro přesměrování HTTP → HTTPS:
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
Nyní je vaše aplikace dostupná přes HTTPS a port 3000 je blokován firewallem před externím přístupem. Nahraďte example.com vaší skutečnou doménou ve všech konfiguracích.
Pokud vaše aplikace kromě API také servíruje statické soubory (obrázky, CSS, JavaScript pro frontend) — přidejte samostatný location blok aby je Nginx servíroval přímo bez zatížení Node.js:
location /static/ {
alias /home/nodeapp/your-app/public/;
expires 30d;
add_header Cache-Control "public, immutable";
}
To výrazně sníží zátěž Node.js procesů — Nginx servíruje statický obsah z disku desítkykrát efektivněji.
Bezpečnost Node.js v production
Firewall a SSH klíče jsou základní úroveň. Pro Node.js existují další vektory útoku, na které se často zapomíná. npm ekosystém — to jsou tisíce závislostí a každá z nich je potenciální vstupní bod. A výchozí HTTP hlavičky odhalují informace o vašem stacku, které pomáhají útočníkům.
Helmet.js
Sada middleware, která nastavuje bezpečné HTTP hlavičky. Bez Helmet vaše Express aplikace odpovídá s výchozími hlavičkami, které odhalují technologický stack (např. X-Powered-By: Express) a nechrání před základními útoky. Helmet jedním řádkem kódu uzavře tucet běžných zranitelností — XSS, clickjacking, MIME sniffing:
const helmet = require('helmet');
app.use(helmet());
Rate Limiting
Omezuje počet požadavků z jedné IP adresy za časový úsek. Bez rate limitingu může automatický skript odeslat tisíce požadavků za sekundu — hrubou silou zkoušet hesla, stahovat obsah nebo jednoduše zahltit vaše API nadměrnou zátěží:
const rateLimit = require('express-rate-limit');
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minut
max: 100 // maximálně 100 požadavků
}));
Pro autorizační endpointy nastavte samostatný, přísnější limit — například 5 pokusů za 15 minut. Pro robustnější ochranu — přidejte rate limiting i na úrovni Nginx přes direktivu limit_req. Dvě úrovně omezení jsou spolehlivější než jedna: Nginx odmítne nadbytečné požadavky ještě předtím, než se dostanou k Node.js.
npm audit
Pravidelně kontrolujte zranitelnosti v závislostech:
npm audit
npm audit fix
Zahrňte to do CI/CD nebo alespoň spouštějte před každým nasazením. Průměrný Node.js projekt má stovky tranzitivních závislostí — knihoven, které stahují další knihovny, které stahují ještě další. Jedna zranitelná knihovna někde na třetí úrovni vnoření může kompromitovat celý server. V posledních letech došlo k několika závažným incidentům s npm balíčky, které kradly proměnné prostředí — tedy hesla k databázím a API klíče.
⚠️ Připomínka: Node.js proces by nikdy neměl běžet jako root. Samostatný uživatel s omezenými právy není doporučení — je to požadavek pro production.
Optimalizace výkonu a monitoring
Aplikace běží, Nginx proxy provoz, PM2 hlídá procesy — základní nastavení je hotové. Nyní je čas zajistit, aby vše fungovalo nejen správně, ale i rychle. Tři nástroje, které přinášejí největší nárůst výkonu: Redis pro cachování, Gzip pro kompresi odpovědí a správný monitoring, abyste viděli kde jsou úzká místa.
Redis pro cachování
Pokud vaše aplikace často sahá do databáze se stejnými dotazy — Redis zásadně mění situaci. V případě eCommerce API z úvodu bylo právě zavedení Redis cachování pro těžké SQL dotazy do katalogu produktů jedním ze tří faktorů, které snížily dobu odpovědi z 850 na 120 ms.
Instalace na Ubuntu:
sudo apt install redis-server -y
sudo systemctl enable redis-server
Princip je jednoduchý: před dotazem do databáze — zkontrolovat zda je výsledek v Redis. Pokud ano — vrátit z cache (mikrosekundy místo milisekund). Pokud ne — provést dotaz, uložit výsledek do cache s TTL:
const Redis = require('ioredis');
const redis = new Redis();
async function getProducts(categoryId) {
const cacheKey = `products:${categoryId}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const products = await db.query(
'SELECT * FROM products WHERE category_id = ?',
[categoryId]
);
await redis.set(cacheKey, JSON.stringify(products), 'EX', 300);
return products;
}
TTL (Time To Live) závisí na typu dat: katalog produktů — 5–15 minut, konfigurace — 1 hodina, uživatelské session — až 24 hodin. Hlavní pravidlo: cachujte to, co se čte často a mění zřídka.
Jeden nuance, na který se často zapomíná — invalidace cache. Když administrátor aktualizuje cenu produktu, starý cache musí být smazán. Nejjednodušší přístup — při změně dat smazat odpovídající klíč: await redis.del('products:' + categoryId). Další požadavek půjde přímo do databáze a obnoví cache čerstvými daty.
Gzip komprese přes Nginx
Pokud vaše API vrací JSON — a většina Node.js API přesně to dělá — Gzip komprese sníží objem provozu 5–10×. To je zvláště znatelné na mobilních připojeních a u velkých datových polí. Přidejte do sekce http hlavního konfiguračního souboru Nginx (/etc/nginx/nginx.conf):
gzip on;
gzip_types application/json text/plain application/javascript;
gzip_min_length 1000;
Parametr gzip_min_length znamená, že Nginx nebude komprimovat odpovědi menší než 1000 bajtů — u malých odpovědí režie komprese převyšuje přínos. Klienti rozdíl nepoznají — prohlížeče a HTTP knihovny automaticky dekomprimují Gzip.
Zero-downtime nasazení aktualizací
Když potřebujete aktualizovat kód v production — nezastavujte celou službu. PM2 v cluster režimu podporuje příkaz reload, který restartuje procesy jeden po druhém. Zatímco se jeden worker restartuje s novým kódem, ostatní pokračují ve zpracování požadavků:
cd /home/nodeapp/your-app
git pull origin main
npm install --production
pm2 reload my-app
Uživatelé si ničeho nevšimnou. Pro větší projekty stojí za to nastavit CI/CD pipeline přes GitHub Actions nebo GitLab CI — pak probíhá nasazení automaticky při pushi do main větve. Základní workflow: push → automatický npm audit → npm test → SSH na VPS → git pull → npm install → pm2 reload. Celý cyklus trvá 30–60 sekund.
Monitoring: Prometheus + Grafana
Aplikace běží, ale běží dobře? Bez monitoringu se o problému dozvíte až když si začnou stěžovat klienti — nebo když PM2 restartuje proces už popáté za hodinu. Event Loop Lag postupně roste, paměť uniká, spojení s databází se neuzavírají — to vše je bez nástrojů pro pozorování neviditelné.
Nejlepší stack pro production monitoring Node.js je Prometheus + Grafana. Prometheus sbírá metriky z vaší aplikace přes speciální endpoint (použijte balíček prom-client) a Grafana je vizualizuje v dashboardech s alerty na email nebo Slack. Klíčové metriky:
| Metrika | Co ukazuje | Kdy vyhlásit poplach |
|---|---|---|
| Event Loop Lag | Zpoždění zpracování událostí — nejdůležitější metrika pro Node.js | > 100 ms |
| Process CPU | Zatížení procesoru každým workerem | > 80 % trvale |
| Heap Memory Used | Spotřeba paměti (hledejte trend růstu — to je memory leak) | Trvalý růst bez poklesů |
| Active Handles | Otevřená spojení, soubory, časovače | Náhlý nárůst |
ℹ️ Levnější alternativa: Pokud je Prometheus + Grafana pro váš projekt příliš — PM2 Plus (placená verze PM2) poskytuje základní monitoring s webovým dashboardem bez dalšího nastavování.
Production kontrolní seznam: ověřte před spuštěním
Vše je nakonfigurováno, aplikace běží — ale než pustíte skutečné uživatele, projděte si tento seznam. Každý vynechaný bod je potenciální incident ve 3 ráno. Lepší strávit 15 minut kontrolou teď než hodinu obnovou potom.
💡 Node.js production kontrolní seznam:
☐ Node.js nainstalován přes NVM (ne apt), verze LTS 22.x
☐ Aplikace spuštěna přes PM2 v cluster režimu, ne přes node app.js
☐ PM2 nakonfigurován pro automatický start (pm2 save + pm2 startup)
☐ Nginx reverse proxy před Node.js s SSL přes Let's Encrypt
☐ Port aplikace (3000) uzavřen ve firewallu, otevřeny pouze 80, 443, SSH
☐ Proces běží pod samostatným uživatelem, ne jako root
☐ Hesla, klíče a tokeny v .env souboru, .env v .gitignore
☐ Helmet.js zapnutý pro bezpečné HTTP hlavičky
☐ Rate limiting nakonfigurován (na úrovni aplikace a/nebo Nginx)
☐ npm audit neukazuje kritické zranitelnosti
☐ Logování funguje — pm2 logs ukazuje co se děje
☐ Monitoring je nastavený — víte kdy je něco špatně
Pokud jsou všechny body splněny — vaše Node.js aplikace je připravena na production zátěž. Pokud ne — každý vynechaný bod je potenciální incident ve 3 ráno.
5 chyb, které rozbíjejí Node.js v production
Tyto chyby se opakují z projektu do projektu. Každá vypadá jako maličkost ve fázi vývoje — ale v production pod zátěží se promění ve vážný problém s výpadky, únikem dat nebo degradací výkonu.
| Chyba | Důsledky | Řešení |
|---|---|---|
| Spuštění jako root | Zranitelnost v aplikaci = plný přístup k serveru | Samostatný uživatel s omezenými právy |
| node app.js bez PM2 | Jedna chyba — aplikace je mrtvá, nikdo ji nerestartuje | PM2 s cluster režimem a auto-restartem |
| Node.js poslouchá na portu 80 přímo | Žádné SSL, žádná ochrana před slow loris, žádné vyvažování | Nginx reverse proxy před Node.js |
| Hesla v kódu nebo Gitu | Kdokoliv s přístupem k repozitáři vidí přihlašovací údaje | .env soubor + .gitignore |
| Instalace přes apt install | Zastaralá verze, konflikty mezi projekty, obtížné aktualizace | NVM nebo fnm pro správu verzí |
Všechny tyto chyby spojuje jedno: jsou neviditelné ve fázi vývoje a testování. Problémy začínají teprve když aplikace narazí na reálnou zátěž nebo se stane cílem automatických skenerů — a to je otázka dnů, ne měsíců.
🚀 Připraveni spustit Node.js na spolehlivém VPS?
Výkon vaší aplikace začíná správným serverem. NVMe disky, garantované prostředky, podpora která rozumí Node.js.
💻 Cloud (VPS) Hosting
- Od $19.95/měs (cca 460 Kč) — Začněte malým, škálujte okamžitě
- KVM virtualizace — Garantované prostředky bez oversellingu
- NVMe úložiště — Rychlý výkon pro Node.js
- Root přístup — Plná kontrola: NVM, PM2, Nginx — vše vaše
- 24/7 podpora — <10 min odezva
🖥️ Dedikované Servery
- Od $200/měs (cca 4 600 Kč) — Pro high-load Node.js API
- Vlastní konfigurace — Intel nebo AMD, až 128 jader
- Více lokací — EU + USA
- 99.9% uptime — SLA garance
- DDoS ochrana — V ceně
- Bezplatná migrace — Pomůžeme přenést projekt
💬 Nejste si jistí, kterou variantu potřebujete?
💬 Napište nám a se vším vám pomůžeme!
Často kladené dotazy
- Jakou verzi Node.js zvolit pro production v roce 2026?
LTS 22.x — zlatý standard. Tato verze dostává bezpečnostní záplaty do dubna 2027 a podporuje všechny moderní funkce: aktualizovaný V8 engine, nativní Fetch API, vylepšený ESM. Instalujte přes NVM, ne přes apt.
- Kolik operační paměti potřebuje Node.js na VPS?
Minimum — 2 GB pro malou aplikaci s PM2 a Nginx. Pro API s Redis cachováním a několika workery — od 4 GB. Reálné eCommerce API stabilně běží na 4 GB se 4 PM2 procesy.
- PM2 nebo systemd — co je lepší pro Node.js?
PM2 — pro Node.js je pohodlnější. Cluster režim s vyvažováním zátěže, zero-downtime reload, vestavěný monitoring, ecosystem.config.js — vše rovnou k dispozici. Systemd funguje pro jednoduché služby, ale pro Node.js dává PM2 větší kontrolu.
- Je Nginx povinný, když Node.js sám umí poslouchat na portu 80?
Ano, je. Nginx zajišťuje SSL terminaci, kompresi, statické soubory a chrání před pomalými spojeními (slow loris). Node.js na portu 80 bez Nginx je production bez ochrany.
- Jak aktualizovat Node.js v production bez výpadku?
Přes NVM: nainstalujte novou verzi (
nvm install 22.x), zkontrolujte kompatibilitu, pakpm2 reload all. PM2 v cluster režimu restartuje procesy jeden po druhém — žádný požadavek nebude ztracen.
- Je Redis potřeba pro každý Node.js projekt?
Ne, ne pro každý. Redis přináší maximální efekt když aplikace často provádí stejné databázové dotazy — katalogy produktů, seznamy kategorií, konfigurace. Pro jednoduchý landing page nebo API s unikátními dotazy při každém volání Redis nepřinese znatelný rozdíl.