Skip to content

Level 0 — Fundamental Concepts ​

Before touching a server, you need a mental model of what a server is and what happens between a user typing a URL and your code running. Everything later in this guide is a detail hanging off this chapter.

What is a server? ​

A server is not a special kind of computer. It is a role. Any computer running a program that waits for incoming requests and answers them is a server. Your laptop running pnpm dev is a server.

What makes a production server different is the environment around it:

  • It runs 24/7 in a datacenter with redundant power and network.
  • It has a static public IP address, so the world can find it.
  • It has no monitor or keyboard — you interact with it only over the network, via SSH.
  • It runs no desktop, no browser, no GUI. Just a kernel, system services, and your apps.

What is a VPS? ​

A VPS (Virtual Private Server) is a slice of a big physical machine, given to you as if it were a whole computer.

A provider like Hetzner owns physical servers with, say, 128 CPU cores and 512 GB of RAM. A hypervisor (KVM on most Linux hosts) divides that machine into many isolated virtual machines. You rent one. You get:

  • A guaranteed slice of CPU and RAM
  • Your own disk
  • Your own public IP
  • Full root access — you can install anything, change any setting

You do not get: control over the physical hardware, or protection from the host failing.

VPS vs the alternatives ​

OptionYou manageProvider managesBest for
Shared hostingFiles onlyEverythingStatic sites, WordPress
VPSOS, packages, security, appHardware, networkFull control, small–medium apps
Dedicated serverOS, packages, security, appHardware onlyHigh, sustained load
PaaS (Vercel, Railway)App code onlyEverything elseSpeed of setup, hands-off ops
KubernetesEverything + orchestrationHardwareMany services, many teams

WHEN A VPS IS THE RIGHT CHOICE

A single VPS comfortably serves a Nuxt + NestJS app with thousands of daily users for €5–20/month. Choose it when you want predictable cost and full control. Choose PaaS when your time is worth more than the savings, and Kubernetes only when you genuinely have many services and people.

What is Linux? ​

Linux is the kernel — the core program that talks to hardware, schedules processes, manages memory, and controls access to files and the network. It is not, by itself, a usable system.

A Linux distribution bundles the kernel with everything else: a shell, core utilities, a package manager, an init system, and thousands of installable packages.

Key consequences of the Linux model, which explain a lot of later behaviour:

  • Everything is a file. Disks, network sockets, and even running processes are exposed as files (/dev/sda, /proc/1234). This is why permissions matter so much.
  • Permissions are enforced by the kernel. A process running as user deploy physically cannot read a file that only root can read.
  • Processes are isolated but share the machine. One runaway process can exhaust RAM and get everything else killed.

What is Ubuntu? ​

Ubuntu is a Linux distribution built on Debian, maintained by Canonical. It is the default choice for servers because it has the largest body of documentation and the widest package support.

LTS means Long Term Support. Ubuntu 24.04 LTS ("Noble Numbat") was released in April 2024 and receives free security updates until April 2029 (extendable to 2036 with Ubuntu Pro).

ALWAYS USE LTS IN PRODUCTION

Non-LTS releases (24.10, 25.04) are supported for only 9 months. When support ends, you stop getting security patches. Never run a non-LTS release on a production server.

Version numbering is YY.MM of release: 22.04 = April 2022, 24.04 = April 2024. A new LTS lands every two years, in April.

What is a process? ​

A process is a running instance of a program. When you start your NestJS API, the kernel:

  1. Loads the node binary into memory
  2. Assigns it a PID (Process ID) — a unique number
  3. Gives it its own memory space
  4. Records which user it runs as
  5. Schedules it onto a CPU core

Every process has:

AttributeMeaningHow to see it
PIDUnique process IDps aux
PPIDParent process IDps -ef
UserWhose permissions it runs withps aux (first column)
Working directoryWhere relative paths resolvepwdx <pid>
EnvironmentIts env varscat /proc/<pid>/environ
Open filesFiles and sockets it holdslsof -p <pid>

PID 1 is special: it is systemd on Ubuntu, the first process the kernel starts, and the ancestor of everything else. If a process's parent dies, PID 1 adopts it.

WHY THIS MATTERS FOR DEPLOYMENT

When your SSH session ends, the shell sends SIGHUP to its child processes. If you started your app with pnpm start in that shell, your app dies with the session. This is exactly the problem PM2 and systemd solve — see Level 13.

Signals ​

Processes are controlled by signals:

SignalNumberMeaningCan be caught?
SIGTERM15"Please shut down cleanly"Yes — the graceful path
SIGINT2Ctrl+CYes
SIGHUP1Terminal closed / reload configYes
SIGKILL9Die nowNo — kernel kills it instantly

SIGKILL gives your process no chance to finish in-flight HTTP requests, flush logs, or close database connections. Always try SIGTERM first.

What is a port? ​

An IP address identifies a machine. A port identifies a program on that machine.

Ports are 16-bit numbers: 1–65535. A socket is the pair (IP address, port). Only one process can listen on a given (IP, port, protocol) combination at a time — which is why you get EADDRINUSE when you start two apps on port 3000.

RangeNameNotes
0–1023Well-known / privilegedRequires root (or CAP_NET_BIND_SERVICE) to bind
1024–49151RegisteredWhere application ports live (3000, 5432, 6379)
49152–65535EphemeralAssigned automatically to outgoing connections

Common ports you will meet:

PortServicePublic?
22SSHYes (restricted)
80HTTPYes
443HTTPSYes
3000Nuxt (our convention)No — localhost only
3001NestJS API (our convention)No — localhost only
5432PostgreSQLNever
6379RedisNever

THE MOST COMMON SERIOUS MISTAKE

Binding PostgreSQL or Redis to 0.0.0.0 exposes them to the entire internet. Automated scanners find an open 5432 or 6379 within minutes. Redis with no password is trivially converted into a crypto-miner install. Bind internal services to 127.0.0.1. See Level 5.

Binding: 127.0.0.1 vs 0.0.0.0 ​

This one distinction prevents most accidental exposure:

Bind addressReachable fromUse for
127.0.0.1 (loopback)Only this machineApp servers, databases, Redis
0.0.0.0 (all interfaces)Anywhere the firewall allowsNginx only
10.0.0.5 (private IP)Other servers on the private networkMulti-server setups

Your Nuxt and NestJS processes should listen on 127.0.0.1. Nginx listens on 0.0.0.0:443 and forwards inward. Even if the firewall fails, a 127.0.0.1-bound service is unreachable from outside.

What is an IP address? ​

An IP address is the postal address of a machine on a network.

IPv4 vs IPv6 ​

IPv4IPv6
Format203.0.113.102a01:4f8:c17:1234::1
Size32 bits128 bits
Total addresses~4.3 billion (exhausted)3.4 × 10³⁸
Written as4 decimal octets8 hex groups, :: collapses zeros
DNS recordAAAAA

Both are in active use. Hetzner gives every VPS one IPv4 address and a whole IPv6 /64 block. Configure both an A and an AAAA record so IPv6-only clients (increasingly common on mobile networks) can reach you.

A CLASSIC BUG

If you publish an AAAA record but your firewall or Nginx only listens on IPv4, IPv6 users get timeouts while everything looks fine to you. UFW handles IPv6 when IPV6=yes in /etc/default/ufw (the default on 24.04), and Nginx needs listen [::]:443 ssl; alongside listen 443 ssl;.

Public vs private IP ​

Public IPPrivate IP
Routable on the internetYesNo
Example203.0.113.1010.0.0.5, 192.168.1.20, 172.17.0.2
Assigned byYour providerYour router / cloud private network / Docker
CostUsually paidFree

Reserved private ranges (RFC 1918): 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.

If you later run a second server for the database, connect them over the provider's private network (Hetzner Cloud Networks) using private IPs. Traffic never touches the public internet, and you can firewall the database to accept connections only from 10.0.0.0/8.

TCP vs UDP ​

Both sit on top of IP. IP moves packets; TCP and UDP decide what guarantees you get.

TCPUDP
ConnectionYes — handshake firstNo — fire and forget
Ordering guaranteedYesNo
Delivery guaranteedYes — retransmitsNo
SpeedSlower (overhead)Faster
Used byHTTP, HTTPS, SSH, PostgreSQL, RedisDNS, QUIC/HTTP3, video streaming, games

Everything in this guide uses TCP except DNS lookups (UDP port 53) and, if you enable it, HTTP/3 (QUIC over UDP 443).

The TCP handshake ​

This explains two error messages you will see constantly:

  • Connection refused — the packet reached the machine, but nothing was listening on that port. The server actively said "no". Fast failure.
  • Connection timed out — the packet vanished. A firewall dropped it silently, or the IP is wrong. Slow failure (~30s+).

Learn to distinguish these; they point at completely different causes.

DNS basics ​

DNS (Domain Name System) translates human names into IP addresses. It is a distributed, hierarchical, heavily-cached database.

The key practical consequence is caching. When you change a DNS record, the old value stays in caches around the world until its TTL (Time To Live) expires. A record with TTL 86400 can take a full day to fully propagate. Full details in Level 15.

HTTP vs HTTPS ​

HTTP is the request/response protocol of the web. It is plain text — anyone between the user and your server (their ISP, café WiFi, a compromised router) can read and modify it.

HTTPS is HTTP wrapped in TLS. TLS provides three things:

PropertyMeaningWithout it
EncryptionNobody in the middle can read the trafficPasswords and session cookies are in plain view
IntegrityNobody can modify it undetectedISPs inject ads; attackers inject scripts
AuthenticationYou are talking to the real example.comA DNS hijack sends users to a lookalike

A certificate is a file signed by a Certificate Authority (CA) that binds your domain name to a public key. Browsers trust ~150 CAs by default. Let's Encrypt is a free, automated CA — covered in Level 16.

HTTPS IS NOT OPTIONAL IN 2026

Browsers mark HTTP pages as "Not secure". Service workers, geolocation, clipboard access, and HTTP/2 all require HTTPS. Secure cookies do not work. Search engines rank you lower. There is no cost argument left — Let's Encrypt is free and automated.

Reverse proxy ​

A forward proxy sits in front of clients. A reverse proxy sits in front of servers.

Why not just point the domain straight at Node?

ProblemHow the reverse proxy solves it
Node would need to bind port 443Nginx binds privileged ports; Node stays on 3000 as a normal user
One IP, many appsNginx routes by Host header to different backends
TLS in every appTLS terminates once, in Nginx
Node is slow at static filesNginx serves them directly from disk with sendfile
No compression / caching layerNginx does gzip, brotli, caching, rate limiting
Node crashes → site is downNginx returns a controlled 502 and recovers instantly when the app returns
Slow-client attacks tie up NodeNginx buffers requests and responses

THIS IS THE SINGLE MOST IMPORTANT ARCHITECTURAL DECISION

Every production Node deployment puts a reverse proxy in front. Nginx (or Caddy, or Traefik) is not optional complexity — it is the boundary between the hostile internet and your application.

Application server ​

Your application server is the process that runs your code: node .output/server/index.mjs for Nuxt, node dist/main.js for NestJS.

Rules for production:

  1. Bind to 127.0.0.1, never 0.0.0.0.
  2. Run as a non-root user (deploy).
  3. Run under a process manager so it restarts on crash and on reboot.
  4. Read configuration from environment variables, not hard-coded values.
  5. Handle SIGTERM by finishing in-flight requests, then exiting.

Database server ​

A database server is a long-running process that owns your data on disk and answers queries over a socket.

PostgreSQLRedis
TypeRelational (SQL)Key-value, in-memory
DurabilityACID, crash-safe by designConfigurable, weaker by default
StoresYour source of truthCaches, sessions, queues, pub/sub
Port54326379
Losing it meansDisaster — restore from backupAnnoyance — cold caches, dropped sessions

Both must be reachable only from your application, never from the internet.

What happens when a user opens https://app.example.com ​

This is the whole system in one sequence. Every step maps to a chapter in this guide.

Step by step:

  1. DNS resolution — the browser asks for the IP of app.example.com. Answer: 203.0.113.10. (Level 15)
  2. TCP handshake — the browser opens a TCP connection to port 443. Your firewall must allow this. (Level 5)
  3. TLS handshake — the browser and Nginx negotiate encryption. Nginx presents the Let's Encrypt certificate, selected by SNI (the domain the browser asked for). (Level 16)
  4. HTTP request — now encrypted, GET / arrives with a Host: app.example.com header.
  5. Nginx routing — Nginx matches server_name app.example.com and proxies to 127.0.0.1:3000. (Level 14)
  6. Nuxt SSR — the Nuxt server renders the page, calling your API for data.
  7. NestJS — checks Redis, falls through to PostgreSQL, caches the result. (Levels 9, 10)
  8. Response travels back through Nginx, encrypted, to the browser.
  9. PM2 kept steps 6 and 7 alive the whole time and will restart them if they crash. (Level 13)

When something breaks in production, you debug by walking this chain and asking at each hop: did the request get this far? Chapter 26 is built around exactly that method.

Production Checklist — Level 0 ​

  • [ ] I can explain the difference between "connection refused" and "connection timed out"
  • [ ] I understand why app servers bind to 127.0.0.1 and only Nginx binds to 0.0.0.0
  • [ ] I can name the three guarantees TLS provides
  • [ ] I understand why PostgreSQL and Redis must never be publicly reachable
  • [ ] I can trace the full path of a request from browser to database and back
  • [ ] I know that only LTS Ubuntu releases belong on a production server
  • [ ] I understand that a process started in an SSH session dies when the session ends

Next: Level 1 — Creating and Connecting to a VPS →