VictoriaLogs
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 a 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. An upstream VictoriaLogs binary listens on all interfaces with no authentication. The SecureAnyCloud image closes that gap.
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 VM's first boot. Port 80 only redirects to HTTPS, and no login is ever accepted over plain HTTP.
- A password unique to your VM. Every path except a static
/healthzneeds HTTP Basic Auth as the useradmin, 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, and the password is handed tohtpasswdon standard input, never on a command line. No password is baked into the image, and no two VMs share one. - VictoriaLogs on loopback only. Its HTTP port 9428 is bound to
127.0.0.1and is never reachable from the network, so never open it in a network 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 Azure data disk mounted at
/var/lib/victoria-logs, which you can resize independently of the OS disk. VictoriaLogs will not start on the bare OS disk if that data disk is missing. - Fixed host name and real client addresses. Requests for a host name the VM does not serve are dropped. nginx logs the real client address and overwrites client-supplied
X-Forwarded-Forheaders. Cross-site browser requests that change state are refused. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
On the image: VictoriaLogs 1.53.0 (/usr/local/bin/victoria-logs-prod), the unmodified upstream community release binary under Apache-2.0 with its checksum verified, plus nginx, Ubuntu 24.04 LTS and the Azure Linux agent. VictoriaLogs runs as its own unprivileged victorialogs user with a 30-day retention period by default. Version 1.53.0 is the upstream security release (Go 1.27.1, POST-only delete and internal endpoints).
Default user: azureuser (or the name you choose) | Recommended VM size: Standard_B2s
VictoriaLogs and VictoriaMetrics are trademarks of their respective owners. This image is provided by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by VictoriaMetrics.
Prerequisites
- An active Azure subscription, an SSH key (or a password) and a VNet with a subnet.
- A network security group that allows TCP 22 (SSH) from your own networks and 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 VNet, allow 443 from the VNet address space only. Never open port 9428.
Deploy from the Azure Portal
Search the Azure Marketplace for VictoriaLogs by SecureAnyCloud, choose the plan and select Create.
Pick Standard_B2s or larger, and choose your SSH key or password. In the networking step, attach a network security group that allows inbound 22 and 443, and optionally 80, from your own networks only.
The image brings its own 32 GiB data disk for the logs. You can see it on the Disks tab.
Deploy from the Azure CLI
Replace the values in angle brackets:
RG="victorialogs-prod"; LOCATION="eastus"; VM_NAME="victorialogs-01" IMAGE_URN="sac1647283583153:victorialogs-ubuntu-24-04:default:latest" az group create --name "$RG" --location "$LOCATION" az network nsg create -g "$RG" --name victorialogs-nsg az network nsg rule create -g "$RG" --nsg-name victorialogs-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name victorialogs-nsg --name allow-https --priority 110 \
--source-address-prefixes "<your-client-cidr>" --destination-port-ranges 443 80 --access Allow --protocol Tcp az vm image terms accept --urn "$IMAGE_URN" az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" --size Standard_B2s \
--admin-username azureuser --ssh-key-values ~/.ssh/id_rsa.pub \
--nsg victorialogs-nsg --public-ip-sku StandardConnect and check the services
Connect to the VM over SSH:
ssh azureuser@<vm-public-ip>First boot generates the certificate and the password, then starts nginx in front of VictoriaLogs. Confirm that the services are active:
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 -versionactive active active FIRSTBOOT_DONE victoria-logs-20261001-105650-tags-v1.53.0-0-g915d91904bOnly SSH and nginx listen on public addresses. VictoriaLogs listens on loopback:
sudo ss -Hlntp | awk '{print $4, $6}' | grep -E ':(22|80|443|9428) ' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort0.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"))Get your URL and password
The URLs and the user name are in the root-only credentials file. Print them with:
sudo grep -E '^victorialogs\.(url|ingest_url|username)=' /root/victorialogs-credentials.txtvictorialogs.url=https://<vm-public-ip>/select/vmui/ victorialogs.ingest_url=https://<vm-public-ip>/insert/jsonline victorialogs.username=adminThe password is the victorialogs.password line of the same file: sudo grep '^victorialogs.password=' /root/victorialogs-credentials.txt. It is unique to this VM, so store it in your password manager or secrets store.
The URL uses the VM's public IP address from the Azure Instance Metadata Service, or its private IP when it has no public one. The certificate names that address plus the VM's private IP address, so browsers and agents inside your VNet can use either. Inspect the certificate:
openssl x509 -in /etc/ssl/victorialogs/victorialogs.crt -noout -subject -ext subjectAltName -enddatesubject=CN = <vm-public-ip>, O = sac X509v3 Subject Alternative Name: IP Address:<vm-public-ip>, IP Address:<vm-private-ip>, IP Address:127.0.0.1, DNS:localhost notAfter=<date about 27 months after first boot>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 probes.
The commands below read the password from the credentials file into a shell variable and pass it to curl through a file descriptor, so it 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://<vm-public-ip>/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 VM's own nginx while keeping the real address in the URL, so the certificate check passes. An Azure VM cannot reach its own public IP from inside. From another machine, drop --resolve and use the URL directly.
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 logs 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"}Explore logs in the web UI
Open the victorialogs.url from Step 4 (https://<vm-public-ip>/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, and the Stream fields panel lists the fields that identify your log streams. 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 the JSON tab shows the raw records.
The Overview page summarises everything stored: total lines, ingestion rate, the number of log streams, and the fields with the number of lines that carry each one.
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 VM's certificate so it can verify the connection. Copy the certificate to each agent host first. It is public, not a secret:
scp azureuser@<vm-public-ip>:/etc/ssl/victorialogs/victorialogs.crt ./victorialogs.crtFluent Bit ([OUTPUT] section), sending JSON lines:
[OUTPUT] Name http Match * Host <vm-ip-or-dns-name> 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://<vm-ip-or-dns-name>/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_nameGrafana Alloy, Promtail or any Loki client: use https://<vm-ip-or-dns-name>/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://<vm-ip-or-dns-name>/insert/opentelemetry/v1/logs and a basicauth extension.
Agents in the same VNet can use the VM's private IP address, which the certificate also names. 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=:514to theExecStartline of/etc/systemd/system/victorialogs.service. - Run
sudo systemctl daemon-reload && sudo systemctl restart victorialogs. - Open TCP 514 in the network security group only to your VNet or VPN address ranges, never to
AnyorInternet.
Senders then use the VM's private IP address.
Storage and retention
VictoriaLogs keeps all log data on the dedicated Azure data disk mounted at /var/lib/victoria-logs:
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=UTCLogs older than the retention period (30 days) are deleted automatically. To keep them longer, change -retentionPeriod (for example -retentionPeriod=90d or -retentionPeriod=1y) in /etc/systemd/system/victorialogs.service. Then run sudo systemctl daemon-reload && sudo systemctl restart victorialogs. You can also cap the disk space with -retention.maxDiskSpaceUsageBytes.
To grow the data disk, increase its size in the Azure Portal. Open Disks, select the data disk and choose Size + performance. Azure may ask you to stop the VM first. You can also use az disk update --size-gb. Then extend the file system online:
sudo resize2fs "$(findmnt -no SOURCE /var/lib/victoria-logs)"For backups, take Azure disk snapshots of the data disk or use Azure Backup.
Use your own DNS name or certificate
The served host name is fixed by configuration, never taken from a request. To serve VictoriaLogs under your own DNS name, point the name at the VM and run the helper. It records the name, regenerates the self-signed certificate for it, updates the credentials file and reloads nginx:
sudo victorialogs-set-hostname <your-dns-name>Use a static public IP address or your own DNS name, so the address does not change after a deallocate. A request for a name or address the VM does not serve is dropped. If the dynamic public IP did change, run the helper with the new address.
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 VM behind an Azure Application Gateway with your certificate and let it forward to port 443, with /healthz as the health probe path.
Security notes
VictoriaLogs runs as its own unprivileged user with a read-only system, and it cannot reach the Azure instance metadata service or the wire server. Check the unit settings:
systemctl show victorialogs -p User -p NoNewPrivileges -p ProtectSystem -p ProtectHome
systemctl show victorialogs -p IPAddressDeny --value | tr ' ' '\n' | sortUser=victorialogs ProtectHome=yes ProtectSystem=full NoNewPrivileges=yes 168.63.129.16/32 169.254.169.254/32Root logins, empty passwords and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf, which sorts before every other SSH setting. Whether SSH accepts passwords follows the choice you made when you created the VM, SSH key or password. Check the effective values:
sudo sshd -T | grep -E '^(permitrootlogin|permitemptypasswords|x11forwarding|pubkeyauthentication) 'permitrootlogin no pubkeyauthentication yes x11forwarding no permitemptypasswords noA 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 403Other points:
- VictoriaLogs has a single account. Anyone with the password can ingest, read and delete every log stream, so give each team its own VM if they must not see each other's logs.
- nginx logs the real client address of every request.
X-Forwarded-Forheaders sent by clients are ignored. - Restrict port 443 in the network security group to the networks your users and agents use, and never open 9428.
- The firmware update refresh timer (
fwupd-refresh) is masked, because an Azure VM has no firmware that LVFS can update. - 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 unmodified upstream community binary, not the enterprise edition, and there is no per-user or per-CPU licence fee. The image price covers SecureAnyCloud's hardening, first-boot setup and 24/7 support.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
VictoriaLogs is developed by VictoriaMetrics. For features and LogsQL, see the VictoriaLogs documentation.
Deploy on Azure
Launch VictoriaLogs on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
VictoriaLogs is the fast, cost-efficient log database from the VictoriaMetrics team. It ingests structured and plain text 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. It runs as a single static Go binary with no external storage dependency, so there is no Elasticsearch cluster, no Kibana and no object store to operate.
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 SecureAnyCloud image closes both gaps.
What you get:
- The VictoriaLogs binary at
/usr/local/bin/victoria-logs-prod, running as a dedicated unprivilegedvictorialogssystem account under a systemd service that starts it on boot and restarts it on failure - Stored logs at
/var/lib/victoria-logs, on a dedicated, independently resizable EBS data volume - The database bound to the loopback interface only, and never exposed directly
- An nginx reverse proxy that publishes the web interface, the ingest paths and the query paths on port 80 behind HTTP Basic authentication
- A password 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.txtwith 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 that allows 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
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 SecureAnyCloud listing and choose Select, then choose 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, then 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.
Launch the instance from the AWS CLI
The command below launches an instance from the SecureAnyCloud VictoriaLogs Marketplace AMI into an existing subnet and security group. Replace the values in angle brackets as follows:
- Replace <ami-id> with the AMI ID shown on the Marketplace listing.
- Replace <key-name> with your EC2 key pair name.
- Replace <subnet-id> with your subnet ID.
- Replace <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. You can find it in the EC2 console or with aws ec2 describe-instances.
Connect to your instance
Connect over SSH with your key pair and the login user for your operating system variant. On Ubuntu 24.04, the SSH login user is ubuntu:
ssh -i /path/to/your-key.pem ubuntu@<public-ip>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, and keep it out of shell history and shared terminals.
sudo cat /root/victorialogs-credentials.txtThe 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 from this file into a shell variable, so it is never printed to your terminal.
Confirm that the credentials file is present and 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.txtThe mode must be 600 root:root and the count must be 1.
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. A stream fields sidebar lists the labels found in your data.
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:WARNSelect 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.
Confirm VictoriaLogs is running
Check that both services are active and that the database listens 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/healthzBoth services must report active, the loopback listener count must be 1, and the health endpoint must return HTTP 200. nginx serves the health endpoint itself and deliberately requires no credentials, so load balancer and target group health checks work without an embedded password.
Next, confirm that the database is not reachable on any public interface. This is the most important security property of the image:
ss -tln | awk '{print $4}' | grep -Ec '(^0\.0\.0\.0:9428$|^\*:9428$|^\[::\]:9428$)' || trueThe count must be 0. Everything from outside the instance goes through nginx on port 80.
Confirm the authentication gate
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/queryThe first three must return HTTP 401 and the last must return HTTP 200.
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 - OpenTelemetry and syslog
The command below sends one log line over the native JSON stream protocol and then reads it back with a LogsQL query. This proves 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. That means the exact log line you sent was stored and read back. A newly ingested line becomes queryable within a few seconds, and 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 that targets http://<public-ip>/insert/opentelemetry/v1/logs with the same credentials.
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. The example below lists the most recent lines and fetches one record:
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 echoThe 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 web interface footer links to the full language reference.
Verify the appliance end to end
The image ships a self-test you can run at any time. It proves function rather than liveness. It checks 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.shOn success it prints a single OK-ingest-to-logsql-query-roundtrip-and-basic-auth-gate-proven line. On any failure it exits with a non-zero status.
Check 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. The volume 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/fstabTo 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.
Set retention and disk sizing
Log retention defaults to 30 days. Storage is also 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 and supply 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.
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 and 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.
Back up and maintain the instance
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 a schedule that matches your retention window.
Update operating system packages 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/healthzSupport
This image is published and supported by SecureAnyCloud. Technical support is available 24 hours a day, 7 days a week by email at sales@secureanycloud.com.
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 of 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. SecureAnyCloud is not affiliated with or endorsed by VictoriaMetrics.
Deploy on AWS
Launch VictoriaLogs on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com