Back to tutorials
Tutorial

Log Shipping Tutorial (2026): Centralize Nginx, SSH, and System Logs on a VPS with rsyslog + TLS

Log shipping tutorial for 2026: centralize VPS logs with rsyslog over TLS, retention, and quick incident searches.

By Anurag Singh
Updated on Jun 25, 2026
Category: Tutorial
Share article
Log Shipping Tutorial (2026): Centralize Nginx, SSH, and System Logs on a VPS with rsyslog + TLS

Logs aren’t useful if they disappear with the server. This log shipping tutorial shows how to centralize Nginx, SSH, and core system logs from one or more VPS nodes onto a dedicated log host.

You’ll use rsyslog over TLS. You’ll also add sensible retention and simple search workflows.

The goal is operational. When someone reports “the site was down at 02:13,” you can check auth failures, web errors, and kernel messages in one place.

You avoid SSH’ing into multiple boxes and grepping in the dark.

What you’ll build (and what you need)

You’ll set up:

  • A log receiver (central log VPS) that accepts rsyslog input over TLS on TCP 6514.
  • One or more log senders (your web/mail/app VPS nodes) that forward selected logs securely.
  • File-based storage on the receiver with per-host/per-program paths and rotation.

This tutorial assumes Ubuntu Server 24.04/24.10 or Debian 12/13 on both sides. Commands use sudo.

If you run AlmaLinux/Rocky, the approach is the same. Paths and package names may differ slightly.

If you want the central box handled for you (updates, monitoring, and security baselines), a managed VPS hosting plan is an easy way to run a dedicated “logging + monitoring” node.

This keeps it from becoming another server you have to babysit.

Architecture: keep logs off the workload server

A common “central logging” mistake is writing logs into a different directory on the same server.

That won’t help during disk bloat, compromise, or a provider outage.

Do it properly instead:

  • Run the receiver on a separate VPS (or a dedicated server if you have many nodes).
  • Allow inbound TCP 6514 only from your known server IPs.
  • Use TLS so log contents and metadata aren’t sent in cleartext.

Central logging works best alongside a basic firewall baseline.

If your rules are still in flux, keep this reference nearby: UFW firewall configuration tutorial.

Step 1 — Provision a receiver VPS with enough disk

For a small hosting fleet, a modest receiver is usually enough:

  • 1 vCPU / 1–2 GB RAM is fine for rsyslog-only receiving.
  • Disk is the limiter. Plan at least 40–80 GB if you want 14–30 days of web + auth logs across several sites.

If you’re pulling logs from many client sites or high-traffic Nginx, scale up.

You can also move to a dedicated server.

HostMyCode’s HostMyCode VPS plans work well for a small, single-purpose “log collector” node.

Step 2 — Install rsyslog and prepare directories (receiver)

On the receiver:

sudo apt update
sudo apt install -y rsyslog rsyslog-gnutls logrotate

Create a dedicated base directory for incoming logs.

Keeping them under /var/log/remote makes it clear what’s local versus shipped.

sudo mkdir -p /var/log/remote
sudo chown syslog:adm /var/log/remote
sudo chmod 2750 /var/log/remote

The setgid bit (2) helps new subdirectories inherit the right group ownership under this path.

Step 3 — Generate a small internal CA and server cert (receiver)

You can use a public PKI. For server-to-server log transport, an internal CA is usually simpler.

You’ll create:

  • A CA cert/key (kept on the receiver)
  • A server cert for the receiver

On the receiver:

sudo mkdir -p /etc/rsyslog/certs
cd /etc/rsyslog/certs
sudo openssl genrsa -out ca.key 4096
sudo openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt \
  -subj "/C=US/ST=NA/L=NA/O=HostMyCode-Logs/OU=CA/CN=hostmycode-log-ca"

Create a server key + CSR. Use the receiver’s real hostname (recommended) or IP.

Hostnames make later changes easier if the receiver’s IP ever moves.

sudo openssl genrsa -out server.key 4096
sudo openssl req -new -key server.key -out server.csr \
  -subj "/C=US/ST=NA/L=NA/O=HostMyCode-Logs/OU=Server/CN=logs01.example.com"

Create a certificate with a Subject Alternative Name (SAN). Update the DNS/IP values for your environment.

cat <<'EOF' | sudo tee server.ext
subjectAltName = DNS:logs01.example.com,IP:203.0.113.10
extendedKeyUsage = serverAuth
keyUsage = digitalSignature, keyEncipherment
EOF

sudo openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 1825 -sha256 -extfile server.ext

Lock down permissions:

sudo chown root:root /etc/rsyslog/certs/*
sudo chmod 600 /etc/rsyslog/certs/*.key
sudo chmod 644 /etc/rsyslog/certs/*.crt

Step 4 — Configure rsyslog receiver over TLS (TCP 6514)

Create a dedicated config file:

sudo nano /etc/rsyslog.d/10-remote-tls-receiver.conf

Paste the following.

It uses sane defaults and writes to per-host/per-program files on disk.

# /etc/rsyslog.d/10-remote-tls-receiver.conf

module(load="imtcp")
module(load="gtls")

# TLS settings
global(
  DefaultNetstreamDriver="gtls"
  DefaultNetstreamDriverCAFile="/etc/rsyslog/certs/ca.crt"
  DefaultNetstreamDriverCertFile="/etc/rsyslog/certs/server.crt"
  DefaultNetstreamDriverKeyFile="/etc/rsyslog/certs/server.key"
)

# Template: /var/log/remote/HOST/PROGRAM.log
template(name="RemotePerHostPerProgram" type="string"
  string="/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
)

# Ensure directories exist
module(load="omfile" dirCreateMode="0750" fileCreateMode="0640")

# Listener on TCP 6514 (syslog over TLS)
input(type="imtcp" port="6514" StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="anon")

# Store all remote messages
if ($fromhost-ip != "127.0.0.1") then {
  action(type="omfile" dynaFile="RemotePerHostPerProgram")
  stop
}

Why authmode anon? You still get encryption and receiver certificate validation via your CA.

If you need mutual TLS (client certs), add it later.

For many teams, “TLS + strict IP allowlist” is a strong first step.

Restart rsyslog and confirm it’s listening:

sudo systemctl restart rsyslog
sudo ss -lntp | grep 6514

Step 5 — Lock down the receiver firewall to sender IPs

If you use UFW on the receiver:

sudo ufw allow 22/tcp
sudo ufw allow from 198.51.100.20 to any port 6514 proto tcp
sudo ufw allow from 198.51.100.21 to any port 6514 proto tcp
sudo ufw enable
sudo ufw status verbose

Keep the allowlist tight.

Your receiver shouldn’t accept syslog from the open internet.

Step 6 — Install and configure rsyslog sender (web/app VPS)

On each sender VPS:

sudo apt update
sudo apt install -y rsyslog rsyslog-gnutls

Copy the CA certificate (ca.crt) from the receiver to the sender.

One simple approach:

# On receiver (copy to a safe place temporarily)
sudo cat /etc/rsyslog/certs/ca.crt

Paste it into the sender:

sudo mkdir -p /etc/rsyslog/certs
sudo nano /etc/rsyslog/certs/ca.crt
sudo chmod 644 /etc/rsyslog/certs/ca.crt

Create the sender config:

sudo nano /etc/rsyslog.d/60-remote-forward-tls.conf
# /etc/rsyslog.d/60-remote-forward-tls.conf

module(load="omfwd")
module(load="gtls")

global(
  DefaultNetstreamDriver="gtls"
  DefaultNetstreamDriverCAFile="/etc/rsyslog/certs/ca.crt"
)

# Queue protects you during network hiccups
action(
  type="omfwd"
  target="logs01.example.com"
  port="6514"
  protocol="tcp"
  StreamDriver="gtls"
  StreamDriverMode="1"
  StreamDriverAuthMode="anon"
  action.resumeRetryCount="-1"
  queue.type="linkedList"
  queue.filename="fwdRemote"
  queue.size="50000"
  queue.saveonshutdown="on"
)

Restart rsyslog:

sudo systemctl restart rsyslog

Step 7 — Forward the right logs (not every byte)

Rsyslog can forward a lot by default. For most VPS hosting, start with the highest-signal logs.

  • Auth: SSH logins and sudo usage
  • Web: Nginx/Apache access and error logs
  • System: kernel messages and service failures

System logs are typically already available via syslog/journald and rsyslog.

Web logs usually need an extra step because Nginx writes to files, not syslog.

Step 8 — Ship Nginx access/error logs using imfile

On the sender VPS running Nginx, enable rsyslog’s file input module.

Tag those entries so they land in predictable files on the receiver.

Create:

sudo nano /etc/rsyslog.d/20-imfile-nginx.conf
# /etc/rsyslog.d/20-imfile-nginx.conf
module(load="imfile")

input(type="imfile"
  File="/var/log/nginx/access.log"
  Tag="nginx-access"
  Severity="info"
  Facility="local6"
)

input(type="imfile"
  File="/var/log/nginx/error.log"
  Tag="nginx-error"
  Severity="error"
  Facility="local6"
)

Restart rsyslog and generate a request:

sudo systemctl restart rsyslog
curl -I http://127.0.0.1/

On the receiver, you should see new files under:

/var/log/remote/<sender-hostname>/nginx-access.log
/var/log/remote/<sender-hostname>/nginx-error.log

If nothing shows up, check the chain from left to right:

  • Sender rsyslog status: sudo systemctl status rsyslog --no-pager
  • File permissions on /var/log/nginx/*.log
  • Receiver listener: sudo ss -lntp | grep 6514

Step 9 — Add retention: rotate remote logs safely

Central logging tends to fail in a boring way: the receiver disk fills up.

Rotate early, keep what you actually use, and revisit the policy after a few incidents.

Create a receiver-side logrotate policy:

sudo nano /etc/logrotate.d/remote-rsyslog
/var/log/remote/*/*.log {
  daily
  rotate 14
  compress
  delaycompress
  missingok
  notifempty
  su syslog adm
  create 0640 syslog adm
  sharedscripts
  postrotate
    /usr/lib/rsyslog/rsyslog-rotate || true
  endscript
}

This keeps two weeks by default.

For payment flows, security investigations, or regulated environments, you may keep longer.

Do the disk math first.

Run a dry test:

sudo logrotate -d /etc/logrotate.d/remote-rsyslog

Step 10 — Quick diagnostics: prove TLS and end-to-end delivery

On a sender, generate a syslog message:

logger -p authpriv.notice "test-log-forwarding $(hostname) $(date -Is)"

On the receiver, search for it:

sudo grep -R "test-log-forwarding" /var/log/remote/ -n | tail -n 5

If it’s missing, check the sender queue.

Rsyslog spools during outages and catches up later.

Look for fwdRemote* queue files in /var/spool/rsyslog/ or your distro’s default spool directory.

Step 11 — Make searches fast: a tiny incident-response workflow

You don’t need a SIEM on day one.

You need a small set of commands you can run the same way every time.

  • Find SSH brute force bursts:
    sudo grep -R "Failed password" /var/log/remote/*/sshd.log | tail -n 50
  • See 5xx spikes in Nginx (basic):
    sudo awk '$9 ~ /^5/ {print $0}' /var/log/remote/*/nginx-access.log | tail -n 50
  • Look for service restarts:
    sudo grep -R "Started\|Stopped\|Failed" /var/log/remote/*/systemd.log | tail -n 80

If you outgrow file searches, you can index later (OpenSearch, Loki, etc.).

The file-based baseline is still valuable because it’s easy to audit, back up, and restore.

Common pitfalls (and how to avoid them)

  • Receiver disk fills: monitor disk usage and keep retention realistic. If you’re already battling storage growth, review: VPS cleanup tutorial.
  • Hostname collisions: if multiple servers share a hostname like ubuntu, logs will mix. Set unique hostnames: sudo hostnamectl set-hostname web01.
  • Nginx logs not shipped: you must configure imfile. File logs won’t forward automatically.
  • Firewall blocks TCP 6514: allowlist sender IPs on the receiver, and confirm outbound isn’t blocked on senders.

Hardening upgrades you can add after day one

Once the basics work, these upgrades tend to deliver the most value in day-to-day hosting operations:

  • Mutual TLS (client certs) so only authenticated servers can send logs, even if an attacker spoofs IP routes.
  • Separate receivers per environment (production vs staging) to reduce noise and avoid accidental data leaks.
  • Back up the receiver so logs survive receiver failure. If you want a tested approach, adapt the retention pattern from this: VPS snapshot backup tutorial.

Summary: a reliable logging baseline for VPS hosting

Centralized logs shorten outages, speed up investigations, and make security reviews less guessy.

Rsyslog over TLS remains a dependable baseline in 2026.

It’s predictable, light on resources, and easy to maintain.

If you’re running a small fleet (web + mail + staging) and want a dedicated home for logs, monitoring, and admin tools, start with a separate node on a HostMyCode VPS.

If you’d rather skip patching and security tuning, put the collector on managed VPS hosting and keep your time for client work.

If you’re centralizing logs for client sites, run the receiver on a separate server with stable disk and predictable performance. HostMyCode offers VPS plans that work well for a dedicated log collector, and managed VPS hosting if you want the maintenance handled for you.

FAQ

Do I need mutual TLS (client certificates) for rsyslog log shipping?

Not strictly. TLS with a private CA plus strict IP allowlisting is a strong baseline for most hosting fleets.

Add client certs if your threat model includes route spoofing or multi-tenant sender networks.

Should I ship everything from journald or only specific services?

Start with auth, system, and web logs.

If you ship everything, you’ll pay in disk and noise.

Expand gradually based on incidents you actually investigate.

What port should I use for syslog over TLS?

TCP 6514 is the conventional port for syslog over TLS.

Keep it closed to the public internet and allow only your sender IPs.

Can I use this with cPanel or DirectAdmin servers?

Yes. The receiver setup stays the same.

On the control panel server, forward system/auth logs and add imfile inputs for panel-specific log files you care about.

Log Shipping Tutorial (2026): Centralize Nginx, SSH, and System Logs on a VPS with rsyslog + TLS | HostMyCode