Deployment guide

VictoriaLogs 1.53.0

Overview

VictoriaLogs is a log database from VictoriaMetrics. It accepts structured and plain-text logs over many protocols: its own JSON lines API, the Loki push API, the Elasticsearch bulk API, OpenTelemetry and syslog. It stores them compressed on disk and lets you search and aggregate them with the LogsQL query language, through the built-in web interface (vmui) or plain HTTP. It is a single binary that needs far less memory and disk than a typical Elasticsearch or OpenSearch stack.

This guide covers the VictoriaLogs 1.53.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud log management listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. An upstream VictoriaLogs binary listens on all interfaces with no authentication, and the SecureAnyCloud image changes that.

What you get:

  • HTTPS from the first boot. nginx is the only network entry point. It serves the web UI and every ingest and query API on port 443 with a certificate generated on your instance's first boot. Port 80 only redirects to HTTPS.
  • A password unique to your instance. Every path except a static /healthz needs HTTP Basic Auth as the user admin, including the delete and internal APIs. The password is generated on first boot and written to the root-only file /root/victorialogs-credentials.txt. nginx stores only its bcrypt hash. No password is baked into the image, and no two instances share one.
  • VictoriaLogs on loopback only. Its HTTP port 9428 is bound to 127.0.0.1 and is never reachable from the network, so never open it in a security group. The syslog receiver is off.
  • Fail closed. nginx refuses to start until first boot has written the certificate and the password, so VictoriaLogs is never served without a login.
  • Your logs on their own disk. All log data lives on a dedicated 32 GiB EBS volume mounted at /var/lib/victoria-logs. You can resize it independently of the root volume.
  • Fixed host name and real client addresses. Requests for a host name the instance does not serve are dropped. nginx logs the real client address, overwriting client-supplied X-Forwarded-For headers, and cross-site browser requests that change state are refused.
  • Key-only SSH. Password logins, root logins and X11 forwarding are switched off.
  • Built from source with a current Go. SecureAnyCloud compiles the VictoriaLogs binary from the unmodified v1.53.0 source with Go 1.27.3. The upstream release binary was built with Go 1.27.1 and carries Go standard library security advisories that later Go releases fix. govulncheck reports no known vulnerabilities in the binary on this image.
  • No instance metadata for VictoriaLogs. The VictoriaLogs service is blocked from the EC2 instance metadata endpoint, so it can never read the instance's role credentials.
  • No background firmware check. The fwupd LVFS metadata refresh timer is masked, because EC2 instances have no LVFS-updatable firmware. sudo fwupdmgr refresh still works by hand.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

The image contains VictoriaLogs 1.53.0 (at /usr/local/bin/victoria-logs-prod). This is the community edition, Apache-2.0, compiled by SecureAnyCloud from the unmodified upstream v1.53.0 source with Go 1.27.3. Its licence and build provenance are in /usr/share/doc/victorialogs/. The image also contains nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. VictoriaLogs runs as its own unprivileged victorialogs user, with a 30-day retention period by default.

Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
  • A security group that allows TCP 22 (SSH) from your own networks. It must also allow TCP 443 (the web UI and the ingest and query APIs) from the networks your users and log agents are in. TCP 80 only redirects to HTTPS and is optional. If your agents run inside the same VPC, allow 443 from the VPC CIDR only.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick VictoriaLogs 1.53.0 on Ubuntu 24.04 as the software version, select your Region, and choose Launch through EC2.

Choose m5.large, your key pair and a security group as described above. The AMI brings its own 32 GiB data volume for the logs. If you expect more log data, increase its size on the launch page (see Step 9).

To launch with the AWS CLI instead, replace the values in angle brackets:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=victorialogs}]'
2

Connect to your instance

Connect over SSH as the ubuntu user with the key pair you launched with.

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

First boot generates the certificate and the password, then nginx starts in front of VictoriaLogs. Confirm that all three services are active and first boot has finished.

systemctl is-active victorialogs nginx victorialogs-firstboot
sudo test -f /var/lib/sac/data/victorialogs-firstboot.done && echo FIRSTBOOT_DONE /usr/local/bin/victoria-logs-prod -version
active active active FIRSTBOOT_DONE victoria-logs-20261001-105650-tags-v1.53.0-0-g915d91904b

The binary was compiled from the v1.53.0 source with Go 1.27.3. The build provenance file records the source archive and its tag commit, the toolchain, the exact build command, the binary's checksum and the govulncheck result. It sits next to the Apache-2.0 licence.

sha256sum /usr/local/bin/victoria-logs-prod grep -E '^(source |tag commit|toolchain |binary sha256|govulncheck)' /usr/share/doc/victorialogs/BUILD-PROVENANCE.txt head -3 /usr/share/doc/victorialogs/LICENSE | sed '/^\s*$/d'
b2d92f78d547853461388ff421c3fc2e860cbcd541c0d5f1f465d84714770ee3 /usr/local/bin/victoria-logs-prod source https://github.com/VictoriaMetrics/VictoriaLogs/archive/refs/tags/v1.53.0.tar.gz source sha256 9dab43bfb2ccc2b3009a2e7cacd798f12b561a92f4a29c8a697c60295a383874 tag commit 915d91904bf7f5be66ab00f88947ae7fc1431acc toolchain go1.27.3 linux/amd64, official tarball https://go.dev/dl/go1.27.3.linux-amd64.tar.gz binary sha256 b2d92f78d547853461388ff421c3fc2e860cbcd541c0d5f1f465d84714770ee3 (reproducible: an independent out-of-band build of the same inputs gives the same bytes) govulncheck v1.9.0, source: No vulnerabilities found.; binary: No vulnerabilities found. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/

Only SSH and nginx listen on public addresses. VictoriaLogs listens on loopback.

sudo ss -Hlntp | awk '{print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:9428 users:(("victoria-logs-p")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))
4

Get your URL and password

The URLs and the user name are in the root-only credentials file.

sudo grep -E '^victorialogs\.(url|ingest_url|username)=' /root/victorialogs-credentials.txt
victorialogs.url=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/select/vmui/ victorialogs.ingest_url=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/insert/jsonline victorialogs.username=admin

The password is the victorialogs.password line of the same file: sudo grep '^victorialogs.password=' /root/victorialogs-credentials.txt. It is unique to this instance, so store it in your password manager or secrets store.

The URL uses the instance's public DNS name from EC2 instance metadata (IMDSv2). If the instance has no public name, it uses the public or private IPv4 address. The certificate names that host plus the instance's public and private IP addresses, so browsers and agents can use any of them.

openssl x509 -in /etc/ssl/victorialogs/victorialogs.crt -noout -subject -ext subjectAltName -enddate
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost notAfter=<date about 27 months after first boot>
5

Check the login

Without the password, every path is refused. A wrong password is refused, and port 80 redirects to HTTPS. With the password, the web UI answers. /healthz answers without a login, for load balancer health checks.

The commands below read the password from the credentials file into a shell variable and pass it to curl through a file descriptor. The password never appears in the process list or your shell history.

H=$(sudo sed -n 's#^victorialogs\.url=https://\([^/]*\)/.*#\1#p' /root/victorialogs-credentials.txt)
PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt) CA=/etc/ssl/victorialogs/victorialogs.crt curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/select/vmui/" curl -s -o /dev/null -w 'no login -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/select/vmui/" curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -u admin:not-the-password "https://$H/select/vmui/" curl -s -o /dev/null -w 'admin + password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") "https://$H/select/vmui/" curl -s -w ' <- /healthz (no login) HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/healthz"
http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/select/vmui/ no login -> HTTP 401 wrong password -> HTTP 401 admin + password -> HTTP 200 ok <- /healthz (no login) HTTP 200

--resolve sends the request to this instance while keeping the real host name, so the certificate check passes. From another machine, drop --resolve and use the URL directly.

6

Send logs and query them with LogsQL

The JSON lines API takes one JSON object per line. The query string names the field that holds the message (_msg_field), the timestamp field (_time_field, where 0 means now) and the fields that identify a log stream (_stream_fields).

Send twelve sample lines, then query them back.

H=$(sudo sed -n 's#^victorialogs\.url=https://\([^/]*\)/.*#\1#p' /root/victorialogs-credentials.txt)
PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt) CA=/etc/ssl/victorialogs/victorialogs.crt for svc in web-01 web-02 db-01; do for lvl in info info warn error; do printf '{"_msg":"%s request handled on %s","_time":"0","service":"checkout","host":"%s","level":"%s"}\n' "$lvl" "$svc" "$svc" "$lvl" done done | curl -s -o /dev/null -w 'ingest -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" \
  -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Content-Type: application/stream+json' --data-binary @- \
  "https://$H/insert/jsonline?_stream_fields=service,host&_time_field=_time&_msg_field=_msg" sleep 2 curl -s --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") \
  --data-urlencode 'query=level:error | fields host, level, _msg | sort by (host)' \
  "https://$H/select/logsql/query" curl -s --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") \
  --data-urlencode 'query=service:checkout | stats by (level) count() as lines | sort by (level)' \
  "https://$H/select/logsql/query"
ingest -> HTTP 200 {"host":"db-01","level":"error","_msg":"error request handled on db-01"} {"host":"web-01","level":"error","_msg":"error request handled on web-01"} {"host":"web-02","level":"error","_msg":"error request handled on web-02"} {"level":"error","lines":"3"} {"level":"info","lines":"6"} {"level":"warn","lines":"3"}

The first query filters on a field and picks the fields to return. The second counts lines per level with the stats pipe. The LogsQL documentation lists every filter and pipe.

VictoriaLogs also accepts the Loki push API, so agents already configured for Grafana Loki can send here unchanged.

H=$(sudo sed -n 's#^victorialogs\.url=https://\([^/]*\)/.*#\1#p' /root/victorialogs-credentials.txt)
PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt) CA=/etc/ssl/victorialogs/victorialogs.crt
TS=$(date +%s%N)
curl -s -o /dev/null -w 'loki push -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" \
  -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Content-Type: application/json' \
  -d "{\"streams\":[{\"stream\":{\"job\":\"guide-test\"},\"values\":[[\"$TS\",\"hello from the Loki push API\"]]}]}" \
  "https://$H/insert/loki/api/v1/push" sleep 2
curl -s --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") \
  --data-urlencode 'query=job:guide-test | fields job, _msg' "https://$H/select/logsql/query"
loki push -> HTTP 204 {"job":"guide-test","_msg":"hello from the Loki push API"}
7

Explore logs in the web UI

Open the victorialogs.url from Step 4 (https://<your-host>/select/vmui/) in a browser. The certificate is self-signed, so the browser warns once. Accept it, or install your own certificate (Step 10). Sign in as admin with the password from the credentials file.

Type a LogsQL query, for example service:checkout, choose a time range and press Execute. The hits histogram shows when the lines arrived. The Stream fields panel lists the fields that identify your log streams, and the results are grouped by stream with color-coded levels.

Narrow the search with a filter such as level:error.

The Table tab shows each line as a row with one column per field, and JSON shows the raw records.

The Overview page summarizes everything stored: total lines, ingestion rate, the number of log streams, and the fields with how many lines carry each one.

8

Send logs from your servers

Any agent that speaks one of the supported APIs works. Give it the URL, the user admin, the password and the instance's certificate, so it can verify the connection. Copy the certificate to each agent host first. It is public, not a secret.

scp -i <your-key.pem> ubuntu@<victorialogs-host>:/etc/ssl/victorialogs/victorialogs.crt ./victorialogs.crt

Fluent Bit ([OUTPUT] section), sending JSON lines:

[OUTPUT] Name http Match * Host <victorialogs-host> Port 443 URI /insert/jsonline?_stream_fields=stream,host&_msg_field=log&_time_field=date Format json_lines Json_date_format iso8601 tls On tls.verify On tls.ca_file /etc/fluent-bit/victorialogs.crt http_User admin http_Passwd <VICTORIALOGS_PASSWORD>

Vector (vector.yaml), using the Elasticsearch-compatible API:

sinks: victorialogs: type: elasticsearch inputs: [your_source] endpoints: ["https://<victorialogs-host>/insert/elasticsearch/"] api_version: v8 compression: gzip healthcheck: enabled: false auth: strategy: basic user: admin password: <VICTORIALOGS_PASSWORD> tls: ca_file: /etc/vector/victorialogs.crt query: _msg_field: message _time_field: timestamp _stream_fields: host,container_name

Grafana Alloy, Promtail or any Loki client: use https://<victorialogs-host>/insert/loki/api/v1/push as the push URL with basic auth admin and the password. OpenTelemetry Collector: use an otlphttp exporter with logs_endpoint: https://<victorialogs-host>/insert/opentelemetry/v1/logs and a basicauth extension.

Keep the password in the agent's own secret store or a root-only file, not in a world-readable configuration. Agents send no browser Origin header, so the image's cross-site request guard does not affect them.

Syslog (optional). The syslog receiver is off because syslog has no authentication. To receive syslog from hosts in your own network, take these steps:

  • Add -syslog.listenAddr.tcp=:514 to the ExecStart line of /etc/systemd/system/victorialogs.service.
  • Run sudo systemctl daemon-reload && sudo systemctl restart victorialogs.
  • Open TCP 514 in the security group only to your VPC or VPN CIDRs, never to 0.0.0.0/0.

Senders then use the instance's private IP address.

9

Storage and retention

VictoriaLogs keeps all log data on the dedicated EBS volume mounted at /var/lib/victoria-logs. Check its usage and the service settings.

sudo du -sh /var/lib/victoria-logs df -h /var/lib/victoria-logs | tail -1 | awk '{print $2" total, "$4" free on "$6}' systemctl cat victorialogs | grep -E '^\s+-'
156K /var/lib/victoria-logs 32G total, 30G free on /var/lib/victoria-logs -httpListenAddr=127.0.0.1:9428 \
  -storageDataPath=/var/lib/victoria-logs \
  -retentionPeriod=30d \
  -loggerTimezone=UTC

Logs older than the retention period (30 days) are deleted automatically. To keep them longer, change -retentionPeriod in /etc/systemd/system/victorialogs.service, for example to -retentionPeriod=90d or -retentionPeriod=1y. Then run sudo systemctl daemon-reload && sudo systemctl restart victorialogs. You can also cap the disk space with -retention.maxDiskSpaceUsageBytes.

To grow the volume, modify it in the EC2 console (Volumes, Modify volume). Then extend the file system online.

sudo resize2fs "$(findmnt -no SOURCE /var/lib/victoria-logs)"

For backups, take EBS snapshots of the data volume.

10

Use your own DNS name or certificate

The served host name is fixed by configuration and never taken from a request. To serve VictoriaLogs under your own DNS name, point the name at the instance and run the helper. The helper records the name, regenerates the self-signed certificate for it, updates the credentials file and reloads nginx.

sudo victorialogs-set-hostname <your-dns-name>

If the instance's public DNS name changes after a stop and start, run the same command again, because a request for a name the instance does not serve is dropped. An Elastic IP avoids this.

To use a certificate from your own CA or a public CA instead, replace /etc/ssl/victorialogs/victorialogs.crt (full chain) and /etc/ssl/victorialogs/victorialogs.key (mode 0600, owner root). Then run sudo nginx -t && sudo systemctl reload nginx.

Alternatively, put the instance behind an Application Load Balancer with an AWS Certificate Manager certificate. Let the load balancer forward to port 443, with /healthz as the health check path.

11

Security notes

VictoriaLogs runs as its own unprivileged user with a read-only system, and it cannot reach the instance metadata endpoint.

systemctl show victorialogs -p User -p NoNewPrivileges -p ProtectSystem -p ProtectHome -p IPAddressDeny
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 User=victorialogs ProtectHome=yes ProtectSystem=full NoNewPrivileges=yes

SSH accepts keys only. Passwords, root logins and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf, which sorts before every other SSH setting. Check the effective values.

sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|x11forwarding|pubkeyauthentication) '
permitrootlogin no pubkeyauthentication yes passwordauthentication no kbdinteractiveauthentication no x11forwarding no

A state-changing request that carries a foreign browser Origin is refused, even with the right password. A web page therefore cannot write to or delete from VictoriaLogs through a signed-in browser.

H=$(sudo sed -n 's#^victorialogs\.url=https://\([^/]*\)/.*#\1#p' /root/victorialogs-credentials.txt)
PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt) CA=/etc/ssl/victorialogs/victorialogs.crt curl -s -o /dev/null -w 'Origin evil.example ingest -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Origin: https://evil.example' -H 'Content-Type: application/json' -d '{"_msg":"x"}' "https://$H/insert/jsonline"
Origin evil.example ingest -> HTTP 403

Keep these points in mind:

  • VictoriaLogs has a single account. Anyone with the password can ingest, read and delete every log stream. Give each team its own instance if they must not see each other's logs.
  • nginx logs the real client address of every request and ignores X-Forwarded-For headers sent by clients.
  • SSH accepts key logins as ubuntu only, with no passwords, no root login and no X11 forwarding. Use sudo for administration.
  • The VictoriaLogs service is denied the instance metadata endpoint (IPAddressDeny in /etc/systemd/system/victorialogs.service.d/50-sac-imds-deny.conf), and it fetches no remote URLs.
  • The AMI requires IMDSv2. Restrict port 443 to the networks your users and agents use, and never open 9428.
  • To rotate the password, generate a new one and write its bcrypt hash with sudo htpasswd -iB /etc/nginx/.victorialogs.htpasswd admin, which reads the new password from standard input. Then update /root/victorialogs-credentials.txt, reload nginx and update your agents.

Support and licensing

VictoriaLogs is open source under the Apache License 2.0. The image ships the community edition, not the enterprise edition, compiled by SecureAnyCloud from the unmodified upstream v1.53.0 source (see /usr/share/doc/victorialogs/BUILD-PROVENANCE.txt). There is no per-user or per-CPU licence fee. The AMI price covers SecureAnyCloud's hardening, first-boot setup and support.

  • Email: sales@secureanycloud.com
  • Website: https://secureanycloud.com

VictoriaLogs is developed by VictoriaMetrics. For features and LogsQL, see the upstream VictoriaLogs documentation.

VictoriaLogs and VictoriaMetrics are trademarks of VictoriaMetrics, Inc. SecureAnyCloud is not affiliated with or endorsed by VictoriaMetrics. The names are used only to identify the upstream software, built here from its unmodified source.

Deploy on AWS

Launch VictoriaLogs 1.53.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS