How to Configure Secure Log Transmission to Remote Journal Servers in Ubuntu Using systemd-journal-upload

In distributed Linux environments, aggregating system logs into a centralised repository is fundamental for audit compliance, incident response, and performance analytics. While legacy systems frequently rely on syslog daemons, modern systemd-based Linux distributions such as Ubuntu offer a native, highly structured streaming mechanism through systemd-journal-upload. This service reads binary log entries directly from the local journal and securely forwards them across the network to a centralised systemd-journal-remote instance using encrypted HTTPS transports and mutual Transport Layer Security (mTLS).

Architecture of systemd-journal-upload and Remote Streaming

The standard systemd journal stores structured binary events containing detailed key-value metadata, including process IDs, systemd unit names, audit session identifiers, and kernel timestamps. When streaming logs to an external host, traditional syslog protocols often discard this rich metadata or require complex parsing pipelines. In contrast, systemd-journal-upload preserves the native Journal Export Format (a serialised stream of field-value pairs), ensuring zero information loss during transit.

The upload workflow operates through an HTTP or HTTPS client built into systemd. It maintains an internal cursor tracking the last successfully transmitted entry. If network connectivity drops or the remote collector becomes temporarily unavailable, systemd-journal-upload pauses transmission without data loss. Upon network restoration, it resumes streaming exactly from its saved cursor position.

Installing and Enabling systemd-journal-upload on Ubuntu

On Ubuntu Server and desktop installations, the remote journaling tools are packaged separately from the minimal systemd core. Before configuring the client, install the systemd-journal-remote package, which provides both the upload client and remote listener binaries:

sudo apt update
sudo apt install -y systemd-journal-remote

Once installed, verify the binary and service definition are present in the system:

systemctl status systemd-journal-upload.service

By default, the service remains inactive until a destination server is specified in its configuration file.

Configuring TLS Certificates for Mutual Authentication

Because journal logs can expose sensitive system variables, network configurations, and diagnostic telemetry, encrypting log traffic across the network is critical. systemd-journal-upload natively supports TLS encryption alongside mutual certificate authentication (mTLS) to prevent unauthorised log interception and spoofing.

To establish secure mutual TLS, ensure you have provisioned three certificate files from your internal Certificate Authority (CA):

  • Trusted CA Certificate: /etc/ssl/certs/journal-ca.pem (Used to validate the remote collector’s TLS identity)
  • Client Certificate: /etc/ssl/certs/journal-client.pem (Sent to the remote collector to prove client identity)
  • Client Private Key: /etc/ssl/private/journal-client.key (Private key securing the client’s TLS session)

Assign strict permissions to the private key so only root and the systemd-journal-upload system user can access it:

sudo chown root:systemd-journal-upload /etc/ssl/private/journal-client.key
sudo chmod 0640 /etc/ssl/private/journal-client.key

Configuring /etc/systemd/journal-upload.conf

The operational behaviour of the upload daemon is governed by /etc/systemd/journal-upload.conf. Open the configuration file in an editor:

sudo nano /etc/systemd/journal-upload.conf

Configure the [Upload] directive with the target server address, network port, and certificate paths:

[Upload]
URL=https://collector.internal.infra.net:19532
ServerKeyFile=/etc/ssl/private/journal-client.key
ServerCertificateFile=/etc/ssl/certs/journal-client.pem
TrustedCertificateFile=/etc/ssl/certs/journal-ca.pem
NetworkTimeoutSec=30s

Key configuration parameters include:

  • URL: Specifies the destination schema, remote collector hostname, and port. The standard port for systemd-journal-remote is 19532.
  • ServerKeyFile: Path to the client’s private key used for TLS client authentication.
  • ServerCertificateFile: Path to the X.509 client certificate presented to the receiving server.
  • TrustedCertificateFile: Path to the root CA certificate used to verify the server’s identity.
  • NetworkTimeoutSec: Maximum period to wait before retrying network sockets if the collector does not acknowledge packets.

Managing the Upload Cursor and State Tracking

To prevent duplicate transmissions and ensure uninterrupted log continuity across service restarts, systemd-journal-upload stores its persistent cursor in /var/lib/systemd/journal-upload/state. You can inspect the current state file to verify transmission checkpoints:

sudo cat /var/lib/systemd/journal-upload/state

The state file records the monotonic cursor position matching the last successfully written log entry:

# State file for systemd-journal-upload
LAST_INDEX=84920
CURSOR=s=9f2c3d4e5a6b7c8d9e0f1a2b3c4d5e6f;i=14bc8;b=a1b2c3d4e5f64a7b8c9d0e1f2a3b4c5d;m=3a4b5c6d;t=624b5c6d7e8f0;x=1a2b3c4d5e6f7a8b

If you need to force a full re-transmission of all logs from the beginning of the local journal storage, stop the service, delete this state file, and restart the daemon.

Starting and Verifying the Upload Service

Once the configuration and certificates are validated, enable and start the upload daemon using systemctl:

sudo systemctl daemon-reload
sudo systemctl enable --now systemd-journal-upload.service

Check the active execution status to ensure the client has successfully established an HTTPS handshake with the collector:

systemctl status systemd-journal-upload.service

A healthy service will report an active running status:

● systemd-journal-upload.service - Journal Remote Upload Service
     Loaded: loaded (/lib/systemd/system/systemd-journal-upload.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-11-08 14:45:00 UTC; 5m ago
   Main PID: 28415 (systemd-journal)
     Status: "Processing input..."
      Tasks: 1 (limit: 4614)
     Memory: 4.8M
        CPU: 180ms
     CGroup: /system.slice/systemd-journal-upload.service
             └─28415 /lib/systemd/systemd-journal-upload --save-state

Testing and Troubleshooting Log Transmission

To verify end-to-end functionality, generate a distinctive test message in the local journal using logger or systemd-cat:

echo "SECURE_AUDIT_PROBE: $(date) - Journal streaming verification" | systemd-cat -t audit-probe -p info

On the destination remote collector, inspect the incoming journal directory (typically /var/log/journal/remote/) using journalctl:

journalctl --directory=/var/log/journal/remote -u audit-probe -n 5

If the upload daemon encounters issues, run it interactively in debug mode by temporarily stopping the background service and invoking the binary directly from the terminal:

sudo systemctl stop systemd-journal-upload.service
sudo /lib/systemd/systemd-journal-upload --save-state --debug

Common operational pitfalls include certificate common name mismatches, untrusted CA chains, and restrictive egress firewall rules blocking destination port 19532. Verifying network connectivity with openssl s_client -connect collector.internal.infra.net:19532 -CAfile /etc/ssl/certs/journal-ca.pem provides immediate confirmation of TLS negotiation before returning the daemon to systemd supervision.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.