Developer Tools AWS

VictoriaLogs on AWS User Guide

| Product: VictoriaLogs on AWS

Overview

This image runs VictoriaLogs, the fast, cost efficient log database from the VictoriaMetrics team. It ingests structured and plaintext logs over many protocols, stores them compactly on disk, and queries them back with the LogsQL query language through a built in browser interface and HTTP APIs, from a single static Go binary with no external storage dependency. There is no Elasticsearch cluster, no Kibana and no object store to operate.

The VictoriaLogs binary is installed at /usr/local/bin/victoria-logs-prod and runs as a dedicated unprivileged victorialogs system account under a systemd service that starts it on boot and restarts it on failure. Stored logs live at /var/lib/victoria-logs, which is a dedicated, independently resizable EBS data volume.

VictoriaLogs ships with no built in authentication of any kind. For a log store that matters twice over: an open ingest endpoint lets anyone write or poison the store, and an open query endpoint leaks every log line in it, including hostnames, URLs, user identifiers, tokens and internal topology. This image therefore binds the database to the loopback interface only and never exposes it directly. An nginx reverse proxy publishes the web interface, the ingest paths and the query paths on port 80 behind HTTP Basic authentication. The password is generated on the first boot of every deployed instance, so two instances launched from the same Amazon Machine Image never share a password. It is written to /root/victorialogs-credentials.txt with mode 0600 so only the root user can read it.

Prerequisites

Before you deploy this image you need:

  • An Amazon Web Services account where you can launch EC2 instances
  • IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
  • An EC2 key pair in the target Region for SSH access to the instance
  • A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and port 80 for the web interface, the ingest paths and the query paths
  • The AWS CLI (version 2) installed locally if you plan to deploy from the command line

Step 1: Launch the Instance from the AWS Marketplace

Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for VictoriaLogs. Select the cloudimg listing and choose Select, then Continue on the subscription summary.

Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that opens port 22 from your management network and port 80 for the web interface and the APIs. Leave the root volume at the default size or larger.

Select Launch instance. First boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg VictoriaLogs Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 80 as described above.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=victorialogs}]'

When the instance reaches the Running state and its status checks pass, note its public IP address or DNS name from the EC2 console or with aws ec2 describe-instances.

Step 3: Connect to Your Instance

Connect over SSH using your key pair and the login user for your operating system variant.

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/your-key.pem ubuntu@<public-ip>

Step 4: Retrieve the Password

The web interface password is generated on first boot and stored in a root only file. Read it on the instance with the command below. Keep it out of shell history and out of shared terminals.

sudo cat /root/victorialogs-credentials.txt

The file records the web interface URL, the ingest endpoint, the username admin and the generated password. The commands later in this guide read the password straight out of this file into a shell variable, so it is never printed to your terminal.

Confirm the credentials file is present and correctly locked down without printing its contents:

sudo test -f /root/victorialogs-credentials.txt && echo "credentials file present"
sudo stat -c '%a %U:%G' /root/victorialogs-credentials.txt
sudo grep -c '^victorialogs.password=' /root/victorialogs-credentials.txt

The mode must be 600 root:root and the count must be 1.

Step 5: Sign In to the Web Interface

Open http://<public-ip>/select/vmui/ in a browser. Sign in with the username admin and the password from the previous step. The built in log explorer opens with a query bar, a volume histogram and the matching log lines, alongside a stream fields sidebar for the labels found in your data.

The VictoriaLogs web interface showing stored log lines with a volume histogram and the stream fields sidebar

Enter a query in the Query box and select Execute to filter the stored logs with LogsQL. This query returns every log line whose level field is ERROR or WARN:

level:ERROR OR level:WARN

The log explorer filtered with LogsQL to errors and warnings, showing the matching histogram and results

Select any row to expand it into the full stored record. Every field is listed separately, including the message, the timestamp, the stream labels and any structured fields your log shipper attached, each with copy and filter actions.

An expanded log record showing its message, stream labels, timestamp and every structured field

Step 6: Confirm VictoriaLogs Is Running

Check that both services are active and that the database is listening on the loopback interface only.

systemctl is-active victorialogs.service
systemctl is-active nginx.service
ss -tln | awk '{print $4}' | grep -c '127.0.0.1:9428'
curl -s -o /dev/null -w 'healthz: HTTP %{http_code}\n' http://127.0.0.1/healthz

Both services must report active, the loopback listener count must be 1, and the health endpoint must return HTTP 200. The health endpoint is served by nginx itself and deliberately needs no credentials, so load balancer and target group health checks work without embedding a password.

Confirm the database is not reachable on any public interface. This is the single most important security property of the image:

ss -tln | awk '{print $4}' | grep -Ec '(^0\.0\.0\.0:9428$|^\*:9428$|^\[::\]:9428$)' || true

The count must be 0. Everything from outside the instance goes through nginx on port 80.

Step 7: Confirm the Authentication Gate

Both halves of the appliance, log ingestion and log querying, sit behind the same HTTP Basic authentication gate. Verify that unauthenticated access is refused and that the generated password is accepted. The password is read into a shell variable and never printed.

PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt)
curl -s -o /dev/null -w 'unauthenticated query:  HTTP %{http_code}\n' --data-urlencode 'query=*' http://127.0.0.1/select/logsql/query
curl -s -o /dev/null -w 'unauthenticated ingest: HTTP %{http_code}\n' -X POST -H 'Content-Type: application/stream+json' --data-binary '{"_msg":"probe","_time":"0"}' http://127.0.0.1/insert/jsonline
curl -s -o /dev/null -w 'wrong password:         HTTP %{http_code}\n' -u 'admin:not-the-password' --data-urlencode 'query=*' http://127.0.0.1/select/logsql/query
curl -s -o /dev/null -w 'correct password:       HTTP %{http_code}\n' -u "admin:$PW" --data-urlencode 'query=*' http://127.0.0.1/select/logsql/query

The first three must return HTTP 401 and the last must return HTTP 200.

Step 8: Ship Logs to the Instance

Point any log shipper at the instance's ingest paths on port 80, using the same HTTP Basic credentials. VictoriaLogs accepts logs over several protocols under /insert/: its own JSON stream at /insert/jsonline, Loki push at /insert/loki/api/v1/push, Elasticsearch bulk at /insert/elasticsearch/_bulk, plus OpenTelemetry and syslog.

The block below sends one log line over the native JSON stream protocol and then reads it back with a LogsQL query, proving the full ingest to query round trip on your own instance.

PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt)
MARK="guide-demo-$(date +%s)"
DATA="{\"_msg\":\"$MARK\",\"_time\":\"0\",\"stream\":\"guide-demo\"}"
curl -s -o /dev/null -w 'ingest: HTTP %{http_code}\n' -u "admin:$PW" \
  -H 'Content-Type: application/stream+json' --data-binary "$DATA" \
  'http://127.0.0.1/insert/jsonline?_stream_fields=stream&_time_field=_time&_msg_field=_msg'
FOUND=no
for _ in $(seq 1 20); do
  BODY=$(curl -s -u "admin:$PW" --data-urlencode "query=$MARK" http://127.0.0.1/select/logsql/query)
  case "$BODY" in *"$MARK"*) FOUND=yes; break ;; esac
  sleep 2
done
echo "round trip: log line $MARK returned by LogsQL query: $FOUND"
[ "$FOUND" = yes ]

The ingest must report HTTP 200 and the round trip line must end in yes, meaning the exact log line you sent was stored and read back. A newly ingested line becomes queryable within a few seconds; the loop above allows up to 40. Each run uses a fresh marker so the assertion stays exact however many logs the instance already holds.

To point a Grafana Loki client, Promtail, Fluent Bit or Vector at this instance, use its Loki push endpoint http://<public-ip>/insert/loki/api/v1/push with basic authentication (username admin and your generated password). To point an OpenTelemetry Collector at it, use an OTLP HTTP exporter targeting http://<public-ip>/insert/opentelemetry/v1/logs with the same credentials.

Step 9: Query Logs with LogsQL

LogsQL is the query language for VictoriaLogs. Run queries through the HTTP query API, which returns one JSON object per matching log line. List a few of the most recent lines, and count how many carry an error level:

PW=$(sudo sed -n 's/^victorialogs\.password=//p' /root/victorialogs-credentials.txt)
curl -s -o /dev/null -w 'logsql query API: HTTP %{http_code}\n' -u "admin:$PW" \
  --data-urlencode 'query=*' --data-urlencode 'limit=5' http://127.0.0.1/select/logsql/query
echo "most recent line:"
curl -s -u "admin:$PW" --data-urlencode 'query=*' --data-urlencode 'limit=1' \
  http://127.0.0.1/select/logsql/query | head -c 300
echo

The query API must return HTTP 200. LogsQL supports word and phrase filters, field filters such as level:ERROR, time filters, stream selectors and pipes such as | stats, | sort and | limit. The same queries you type into the web interface work here unchanged, which makes the API convenient for dashboards, alerts and ad hoc searches. The full language reference is linked from the web interface footer.

Step 10: Verify the Appliance End to End

The image ships a self test you can run at any time. It proves function rather than liveness: the health endpoint, the negative controls (unauthenticated ingest refused, unauthenticated query refused, wrong password refused), and a full ingest to LogsQL query round trip that reads the exact log line back.

sudo /usr/local/sbin/victorialogs-selftest.sh

It prints a single OK-ingest-to-logsql-query-roundtrip-and-basic-auth-gate-proven line on success and exits non zero on any failure.

Step 11: The Data Volume

Stored logs live on a dedicated EBS volume mounted at /var/lib/victoria-logs, separate from the operating system disk and independently resizable. It is referenced in /etc/fstab by filesystem UUID, so it remounts correctly on every boot regardless of NVMe device naming.

findmnt -no SOURCE,TARGET,FSTYPE /var/lib/victoria-logs
df -h /var/lib/victoria-logs | tail -1
grep -c 'victoria-logs' /etc/fstab

To grow the store, extend the EBS volume in the AWS console or with aws ec2 modify-volume, then grow the filesystem on the instance with sudo resize2fs. No VictoriaLogs configuration changes are needed.

Step 12: Retention and Disk Sizing

Log retention defaults to 30 days. Storage is additionally capped at 80 percent of the data volume, so a burst of logs can never fill the disk and wedge the service; VictoriaLogs drops the oldest partitions first. Both settings are single flags on the service unit:

systemctl cat victorialogs.service | grep -E 'retentionPeriod|maxDiskUsagePercent|storageDataPath'

To change them, override the unit with sudo systemctl edit victorialogs.service, supplying a replacement ExecStart with your preferred values, then reload and restart the service. Size the data volume against your actual ingest rate; VictoriaLogs stores logs very compactly, but high volume workloads still benefit from a larger volume and a longer retention window.

Step 13: Enable HTTPS

The image serves plain HTTP on port 80 because it ships without a certificate. For production, put a domain in front of the instance and terminate TLS. Point a DNS A record at the instance's public address, open port 443 in the security group, then install a certificate with Let's Encrypt:

sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

Certbot rewrites the nginx server block to listen on 443, installs the certificate and sets up automatic renewal. The HTTP Basic authentication gate is unchanged and continues to protect both the ingest and the query paths. Once TLS is live, update your log shippers to the https:// endpoint.

Step 14: Backup and Maintenance

The log store is at /var/lib/victoria-logs. Because it is a dedicated EBS volume, the simplest backup is an EBS snapshot, which is consistent and needs no application downtime. Snapshot it on whatever schedule matches your retention window.

Operating system packages are updated with the distribution's normal tooling. To move to a newer VictoriaLogs release, replace the binary at /usr/local/bin/victoria-logs-prod with the official upstream build and restart the service. VictoriaLogs maintains on disk format compatibility across releases, so upgrades are normally an in place binary swap; read the upstream release notes before any major version upgrade.

Check service health and recent activity at any time:

systemctl is-active victorialogs.service nginx.service
curl -s -o /dev/null -w 'healthz: HTTP %{http_code}\n' http://127.0.0.1/healthz

Support

This image is published and supported by cloudimg. Technical support is available 24 hours a day, 7 days a week by email at support@cloudimg.co.uk.

Support covers deployment and instance sizing, log shipper configuration against the ingest endpoint (Loki, Fluent Bit, Vector, OpenTelemetry Collector, syslog), retention and disk sizing, TLS termination, nginx and authentication configuration, VictoriaLogs version upgrades, and troubleshooting ingestion, query and connectivity issues. Include your instance ID and AWS Region when you get in touch so we can help faster.

VictoriaLogs and VictoriaMetrics are trademarks of their respective owners. cloudimg is not affiliated with or endorsed by VictoriaMetrics.