Adding syslog-ng to a host to extract Nginx logs

This replaces and combines two earlier posts:

  1. Replacing syslogd with syslog-ng (sysutils/syslog-ng) on FreeBSD.
  2. Getting Nginx logs into Victoria-Logs

I just got Victoria Logs running. Now I want to get logs into it. For starters, I want to get the logs on the host itself into Victoria Logs. I figure this is a log-risk experiment.

In this post:

  • FreeBSD 15.0
  • victoria-logs-1.50.0_2
  • syslog-ng-4.11.0_2
  • I’m installing syslog-ng on a host (x8dtu)
  • The nginx logs reside in a jail (nginx01) on that host

I will be using TLS between syslog-ng and victoria-logs – you will notice this is all on the same host, and some of you might say: you don’t need TLS for that. However, this is a proof-of-concept for remote hosts. They will be passing traffic through my VPN and my network. Or perhaps over the Internet. Things change. Let’s start with TLS.

I know that various tools can be used for testing logs to VictoriaLogs. I should investigate that. Filebeat (now known as beats) has been mentioned.

The install

I installed:

[17:03 x8dtu dvl ~] % sudo pkg install syslog-ng
Updating local repository catalogue...
Fetching meta.conf: 100%     179 B   0.2 kB/s    00:01    
Fetching data: 100%   353 KiB 361.3 kB/s    00:01    
Processing entries: 100%
local repository update completed. 955 packages processed.
All repositories are up to date.
The following 6 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
	glib: 2.86.4,2 [local]
	ivykis: 0.43.2_1 [local]
	json-c: 0.18 [local]
	libuuid: 2.42.1 [local]
	py312-packaging: 26.2 [local]
	syslog-ng: 4.11.0_2 [local]

Number of packages to be installed: 6

The process will require 112 MiB more space.
12 MiB to be downloaded.

Proceed with this action? [y/N]: y
[1/6] Fetching ivykis-0.43.2_1: 100%    70 KiB  71.3 kB/s    00:01    
[2/6] Fetching py312-packaging-26.2: 100%   189 KiB 193.9 kB/s    00:01    
[3/6] Fetching glib-2.86.4,2: 100%    10 MiB   5.5 MB/s    00:02    
[4/6] Fetching syslog-ng-4.11.0_2: 100%  1102 KiB   1.1 MB/s    00:01    
[5/6] Fetching libuuid-2.42.1: 100%    48 KiB  49.5 kB/s    00:01    
[6/6] Fetching json-c-0.18: 100%    71 KiB  73.1 kB/s    00:01    
Checking integrity... done (0 conflicting)
[1/6] Installing ivykis-0.43.2_1...
[1/6] Extracting ivykis-0.43.2_1: 100%
[2/6] Installing json-c-0.18...
[2/6] Extracting json-c-0.18: 100%
[3/6] Installing libuuid-2.42.1...
[3/6] Extracting libuuid-2.42.1: 100%
[4/6] Installing py312-packaging-26.2...
[4/6] Extracting py312-packaging-26.2: 100%
[5/6] Installing glib-2.86.4,2...
[5/6] Extracting glib-2.86.4,2: 100%
[6/6] Installing syslog-ng-4.11.0_2...
[6/6] Extracting syslog-ng-4.11.0_2: 100%
==> Running trigger: glib-schemas.ucl
Compiling glib schemas
No schema files found: doing nothing.
==> Running trigger: gio-modules.ucl
Generating GIO modules cache
=====
Message from syslog-ng-4.11.0_2:

--
syslog-ng is now installed!  To replace FreeBSD's standard syslogd
(/usr/sbin/syslogd), complete these steps:

1. Create a configuration file named /usr/local/etc/syslog-ng.conf
   (a sample named syslog-ng.conf.sample has been included in
   /usr/local/etc). Note that this is a change in 2.0.2
   version, previous ones put the config file in
   /usr/local/etc/syslog-ng/syslog-ng.conf, so if this is an update
   move that file in the right place

2. Configure syslog-ng to start automatically by adding the following
   to /etc/rc.conf:

        syslog_ng_enable="YES"

3. Prevent the standard FreeBSD syslogd from starting automatically by
   adding a line to the end of your /etc/rc.conf file that reads:

        syslogd_enable="NO"

4. Shut down the standard FreeBSD syslogd:

     kill `cat /var/run/syslog.pid`

5. Start syslog-ng:

     /usr/local/etc/rc.d/syslog-ng start

Configuration tweaks & permissions issues

I added this section after publishing the post. There are some permission issues and local logging issues for me to fix. This is how I did that.

By default, syslog-ng does a chmod 0700 when it opens the file. I wanted to preserve existing permissions, mostly for logcheck usage, but also for my sanity. Here are those changes:

[17:18 x8dtu dvl ~] % diff -ruN  /usr/local/etc/syslog-ng.conf.sample /usr/local/etc/syslog-ng.conf

--- /usr/local/etc/syslog-ng.conf.sample	2026-06-18 00:42:01.000000000 +0000
+++ /usr/local/etc/syslog-ng.conf	2026-06-20 17:18:32.813616000 +0000
@@ -20,10 +20,10 @@
 #
 # destinations
 #
-destination messages { file("/var/log/messages"); };
+destination messages { file("/var/log/messages" perm(0644)); };
 destination security { file("/var/log/security"); };
-destination authlog { file("/var/log/auth.log"); };
-destination maillog { file("/var/log/maillog"); };
+destination authlog { file("/var/log/auth.log" perm(0640)); };
+destination maillog { file("/var/log/maillog" perm(0640)); };
 destination lpd-errs { file("/var/log/lpd-errs"); };
 destination xferlog { file("/var/log/xferlog"); };
 destination cron { file("/var/log/cron"); };
[17:18 x8dtu dvl ~] % 

Getting ready

Here, I disable the built-in syslogd and enable the new syslog-ng.

[17:19 x8dtu dvl ~] % sudo service syslogd disable
syslogd disabled in /etc/rc.conf
[17:19 x8dtu dvl ~] % sudo service syslog-ng enable
syslog_ng enabled in /etc/rc.conf
[17:19 x8dtu dvl ~] % 

I’m told the default configuration file works as a drop-in replacement for the system defaults.

Stop, and start:

[17:16 x8dtu dvl ~] % sudo service syslogd onestop
Stopping syslogd.
Waiting for PIDS: 3138.
[17:18 x8dtu dvl ~] % sudo service syslog-ng start
Starting syslog_ng.
[17:19 x8dtu dvl ~] % ps auwwxd | grep syslog
root      845    0.0  0.0  14368   2888  -  Is   10Jun26      0:01.46 |-- rtsold: system.syslog (rtsold)
dvl     21692    0.0  0.0  14164   2680  0  S+   17:19        0:00.00 |       `-- grep syslog
root     4517    0.0  0.0  14428   3216  -  ICsJ 10Jun26      0:06.39 |-- /usr/sbin/syslogd -s
root     4520    0.0  0.0  14428   3076  -  IJ   10Jun26      0:00.01 |-- syslogd: syslogd.casper (syslogd)
root     4521    0.0  0.0  14428   3036  -  IsJ  10Jun26      0:00.00 |-- syslogd: system.net (syslogd)
root     5945    0.0  0.0  14428   3212  -  ICsJ 10Jun26      2:24.58 |-- /usr/sbin/syslogd -s
root     5971    0.0  0.0  14428   3068  -  IJ   10Jun26      0:00.01 |-- syslogd: syslogd.casper (syslogd)
root     5974    0.0  0.0  14428   3032  -  IsJ  10Jun26      0:00.00 |-- syslogd: system.net (syslogd)
root     7993    0.0  0.0  14428   3208  -  SCsJ 10Jun26      0:01.30 |-- /usr/sbin/syslogd -s
root     7996    0.0  0.0  14428   3080  -  IJ   10Jun26      0:00.01 |-- syslogd: syslogd.casper (syslogd)
root     7997    0.0  0.0  14428   3036  -  IsJ  10Jun26      0:00.00 |-- syslogd: system.net (syslogd)
root     8549    0.0  0.0  14428   3296  -  ICsJ 10Jun26      0:16.94 |-- /usr/sbin/syslogd -s
root     8552    0.0  0.0  14428   3132  -  IJ   10Jun26      0:00.02 |-- syslogd: syslogd.casper (syslogd)
root     8553    0.0  0.0  14428   3096  -  IsJ  10Jun26      0:00.00 |-- syslogd: system.net (syslogd)
root    10829    0.0  0.0  14428   3280  -  SCsJ 10Jun26      0:28.53 |-- /usr/sbin/syslogd -s
root    10832    0.0  0.0  14428   3148  -  IJ   10Jun26      0:00.01 |-- syslogd: syslogd.casper (syslogd)
root    10833    0.0  0.0  14428   3104  -  IsJ  10Jun26      0:00.00 |-- syslogd: system.net (syslogd)
root    21680    0.0  0.0  27040  12368  -  S    17:19        0:00.00 |-- /usr/local/sbin/syslog-ng -f /usr/local/etc/syslog-ng.conf -p /var/run/syslog.pid
root    21681    0.0  0.0  40776  15476  -  Ss   17:19        0:00.04 | `-- /usr/local/sbin/syslog-ng -f /usr/local/etc/syslog-ng.conf -p /var/run/syslog.pid

Well, that was painless. However, let’s check logs.

[17:19 x8dtu dvl ~] % logger testing
[17:20 x8dtu dvl ~] % sudo tail /var/log/messages
Jun 20 16:50:46 x8dtu openvpn[3319]: Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 4096 bits RSA, signature: RSA-SHA256, peer signing digest/type: rsa_pss_rsae_sha256 RSASSA-PSS, key agreement: X25519MLKEM768
Jun 20 17:08:34 x8dtu pkg[12806]: ivykis-0.43.2_1 installed
Jun 20 17:08:34 x8dtu pkg[12806]: json-c-0.18 installed
Jun 20 17:08:34 x8dtu pkg[12806]: libuuid-2.42.1 installed
Jun 20 17:08:34 x8dtu pkg[12806]: py312-packaging-26.2 installed
Jun 20 17:08:36 x8dtu pkg[12806]: glib-2.86.4,2 installed
Jun 20 17:08:36 x8dtu pkg[12806]: syslog-ng-4.11.0_2 installed
Jun 20 17:17:54 x8dtu syslogd: exiting on signal 15
Jun 20 17:19:22 x8dtu syslog-ng[21681]: syslog-ng starting up; version='4.11.0'
Jun 20 17:20:00 x8dtu dvl[21757]: testing

That seems to be working.

Next step get logs into victoria-logs.

syslog messages

I’m using include files with my configuration. This is the first of such files. This sends the syslog messages to VictoriaLogs.

[17:32 x8dtu dvl /usr/local/etc] % cat syslog-ng-local-syslog.conf 
template t_victoria_syslog_json {
    template("$(format-json
        _time=$ISODATE
        _msg=$MESSAGE
        host=$HOST
        program=$PROGRAM
    )\n");
};

destination d_victorialogs_syslog_json {
  http(
    persist-name("d_victorialogs_syslog_json")
    url("https://logs.int.unixathome.org:9428/insert/jsonline?_stream_fields=host,program")
    method("POST")
    headers("Content-Type: application/json")
    body(t_victoria_syslog_json)
    tls(peer-verify(yes))
    disk-buffer(
      disk-buf-size(1073741824)
      reliable(yes)
    )
    workers(2)
  );
};

log {
    source(src);
    destination(d_victorialogs_syslog_json);
};

I added the following line to the bottom of /usr/local/etc/syslog-ng.conf:

@include "/usr/local/etc/syslog-ng-local-syslog.conf"

After restarting syslog-ng on x8dtu, I started to see these messages in VictoriaLogs:

{
  "_msg": "syslog-ng starting up; version='4.11.0'",
  "_stream": "{host=\"x8dtu\",program=\"syslog-ng\"}",
  "_stream_id": "0000000000000000f5ee0a1fa8262b11ba75d81442c00a6f",
  "_time": "2026-06-20T17:37:15Z",
  "host": "x8dtu",
  "program": "syslog-ng"
}

Success. Next, nginx logs.

Telling nginx to do JSON

This is the log format I use to tell nginx how to produce JSON:

log_format victorialogs_json escape=json '{'
    '"_time":"$time_iso8601",'
    '"_msg":"$request",'
    '"status":"$status",'
    '"remote_addr":"$remote_addr",'
    '"body_bytes_sent":"$body_bytes_sent",'
    '"request_time":"$request_time",'
    '"http_user_agent":"$http_user_agent",'
    '"app":"nginx",'
    '"http_referer":"$http_referer",'
    '"request_method":"$request_method",'
    '"host":"$host",'
    '"hostname":"$hostname",'
    '"server_name":"$server_name"'
'}';

Note the hardcoded app field.

The log_format statement goes outside the server declaration but inside the http directive.

The log directive, as shown below, goes inside the server declaration. I keep the existing original logs (lines 1-2). The new lines are lines 4-5.

  error_log     /var/log/nginx/freshports.org-error.log;
  access_log    /var/log/nginx/freshports.org-access.log combined;

  # Send JSON format to a log agent or Syslog endpoint handled by VictoriaLogs
  access_log /var/log/nginx/access_json.log victorialogs_json;

Issuing a reload (or restart) will start logging to the new file. That has to be done inside the jail, in my case. I think I could do it from outside, but not today.

Checking the log file, I see this (newlines added to fit on a page):

[17:58 x8dtu-nginx01 dvl /usr/local/etc/freshports] % tail -1  /var/log/nginx/access_json.log
{"_time":"2026-06-20T17:59:14+00:00","_msg":"GET /foo/?branch=2026Q2 HTTP/1.1","status":"403","remote_addr":"71.168.156.244","body_bytes_sent":"183","request_time":"0.000",
"http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_3_1) AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/131.0.6778.204 Safari/537.36","app":"nginx","http_referer":"","request_method":"GET",
"host":"x8dtu.example.org","hostname":"x8dtu-nginx01.vpn.unixathome.org","server_name":"x8dtu.example.org"}

Good.

Next, we tell syslog-ng to pick up and transmit that file to the server.

Sending nginx logs to the server

The following instructs syslog-ng to send the nginx logs to the server.

[17:30 x8dtu dvl ~] % cat /usr/local/etc/syslog-ng-nginx-to-victoria-logs.conf
source s_nginx_json {
  file("/jails/nginx01/var/log/nginx/access_json.log" flags(no-parse) log-msg-size(65536));
};
 
destination d_victorialogs_nginx_json {
  http(
    persist-name("d_victorialogs_nginx_json")
    url("https://logs.int.unixathome.org:9428/insert/jsonline?_stream_fields=host,program")
    method("POST")
    headers("Content-Type: application/json")
    body("${MESSAGE}\n")
    tls(peer-verify(yes))
  );
};
 
log {
  source(s_nginx_json);
  destination(d_victorialogs_nginx_json);
};

Notes:

  • _stream_fields tells VictoriaLogs to use host and program for the _stream value in the stored record.

I added the following line to the bottom of /usr/local/etc/syslog-ng.conf:

@include "syslog-ng-nginx-to-victoria-logs.conf"

Let’s pick up the changes:

[17:57 x8dtu dvl /usr/local/etc] % sudo service syslog-ng restart
Stopping syslog_ng.
Waiting for PIDS: 41691.
Starting syslog_ng.

And boom, this entry was located in VictoriaLogs:

{
  "_msg": "GET /foo/?branch=2026Q2 HTTP/1.1",
  "_stream": "{host=\"x8dtu.example.org\"}",
  "_stream_id": "0000000000000000ad432b7122308cfa678384b77ffc7f89",
  "_time": "2026-06-20T17:59:14Z",
  "app": "nginx",
  "body_bytes_sent": "183",
  "host": "x8dtu.example.org",
  "hostname": "x8dtu-nginx01.vpn.unixathome.org",
  "http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_3_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.204 Safari/537.36",
  "remote_addr": "71.168.156.244",
  "request_method": "GET",
  "request_time": "0.000",
  "server_name": "x8dtu.example.org",
  "status": "403"
}

Success!

Notice how _stream is only the host. Later logs contained both app and host: _stream: “{app=\”nginx\”,host=\”www.freshports.org\”}”

Hope that helps.

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive

Leave a Comment

Scroll to Top