VictoriaTraces
Overview
VictoriaTraces is a distributed tracing database from the VictoriaMetrics project. It receives OpenTelemetry spans over OTLP, stores them compactly on disk with no external database behind it, and serves them back through Jaeger-compatible query APIs and a built-in web UI.
A traditional tracing stack needs a collector, a storage backend such as Cassandra or Elasticsearch, and a separate query service. VictoriaTraces is a single static Go binary that does the storage and the querying itself.
The SecureAnyCloud image installs the pinned VictoriaTraces 0.9.4 binary under systemd, then locks it down for a marketplace appliance. VictoriaTraces has no built-in authentication of any kind. That matters more for a tracing backend than for most services. An open ingest endpoint lets anyone write or poison your trace store, and an open query endpoint exposes every span in it. Spans routinely carry hostnames, URL paths, user identifiers, SQL statements and the topology of your services.
For that reason, the binary is bound to loopback 127.0.0.1:10428, where it is never reachable from outside the VM. An nginx reverse proxy on port 80 puts a per-VM HTTP Basic Auth gate (user admin, unique password generated on first boot) in front of both the ingest path and the query paths. The only unauthenticated route is a static /healthz used by load balancer probes. All stored spans live on a dedicated Azure data disk mounted at /var/lib/victoria-traces.
What you get:
- VictoriaTraces 0.9.4 installed as a single Go binary, running as the
victoriatracessystemd service under a dedicated non-login account. - OTLP over HTTP span ingestion at
/insert/opentelemetry/v1/traces, accepting protobuf or JSON. - Jaeger-compatible query APIs under
/select/jaeger/api/and the built-in web UI at/select/vmui/. - Per-VM HTTP Basic Auth (user
admin) that protects the web UI, the ingest endpoint and every query API. The password is unique, generated on first boot, and there is no default login. - An unauthenticated
/healthzendpoint for Azure Load Balancer health probes. - A dedicated Azure data disk mounted at
/var/lib/victoria-tracesthat holds all span data, with a 7-day default retention and an 80 percent disk usage cap you can tune. - A shipped self test at
/usr/local/sbin/victoriatraces-selftest.shthat proves the auth gate and a full ingest-to-query round trip. - An Ubuntu 24.04 LTS base, patched at build time, with unattended security upgrades enabled.
- 24/7 SecureAnyCloud support.
Project maturity
VictoriaTraces is a young component of the VictoriaMetrics family. Factor that in before you make it the system of record for production tracing.
The project's first release was in July 2025, and it is under active development. Upstream has not yet declared a generally available release. Its own roadmap lists items that must be completed before GA, including "finalize the data structure and commit to backward compatibility", and the version numbering is still 0.x. Upstream does not describe the product as beta or experimental, but it is explicitly pre-GA by its own statement.
The practical consequence is that the on-disk span format is not yet covered by a backward compatibility commitment. A future major upgrade may require re-ingesting your spans instead of upgrading in place. Traces are usually short-lived, high-volume and reproducible, which makes this far less painful than it would be for a metrics or billing store. It is still a real consideration.
Two individual features are separately marked experimental upstream and are deliberately not enabled in this image: the Jaeger service dependency graph API and the Grafana Tempo query APIs.
VictoriaTraces 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 Azure subscription and permission to create a VM.
- An SSH key pair (
ssh-keygen -t ed25519). - Inbound access to port 22 (SSH) and port 80 (the web UI, ingest and query APIs) on the VM, and optionally 443 if you add TLS.
- A recommended size of
Standard_B2sor larger.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure portal, choose Create a resource, search the Marketplace for VictoriaTraces by SecureAnyCloud, and select Create.
On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab, then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:victoriatraces-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name victoriatraces \
--image sac1647283583153:victoriatraces-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name victoriatraces --port 80 --priority 1010Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
Two units make up the appliance. victoriatraces.service is the tracing database itself, bound to loopback. nginx.service is the authenticating reverse proxy, and it is the only service listening on a public interface.
systemctl is-active victoriatraces.service nginx.serviceBoth services should report active. Confirm the listener layout and the dedicated data disk at the same time:
ss -tlnp | grep -E '127.0.0.1:10428 |:80 ' findmnt -no SOURCE,TARGET,FSTYPE,SIZE /var/lib/victoria-tracesVictoriaTraces appears on 127.0.0.1:10428 only. It has no public listener, which is deliberate.
Step 5 - Retrieve your per-VM password
Every VM generates its own web password on first boot. Nothing is baked into the image, so there is no default login to change. Read the credentials file:
sudo cat /root/victoriatraces-credentials.txtThe file is 0600 root:root. It contains the instance URL, the OTLP endpoint, the username admin and the generated password. It also records the pinned runtime configuration.
Step 6 - Understand the security gate
The unauthenticated health endpoint is open so that Azure Load Balancer probes work. nginx serves it directly and it never touches VictoriaTraces, so it exposes nothing about your spans.
curl -s http://localhost/healthzEverything else requires the per-VM credentials. Verify this yourself, because it is the single most important property of the appliance. The following commands prove that both halves are closed to anonymous callers and that only the correct password opens them:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt)
echo "unauth ingest : $(curl -s -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' --data '{}' http://127.0.0.1/insert/opentelemetry/v1/traces)"
echo "unauth query : $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/select/jaeger/api/services)"
echo "unauth web UI : $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/select/vmui/)"
echo "wrong pw : $(curl -s -o /dev/null -w '%{http_code}' -u admin:wrong-pw http://127.0.0.1/select/jaeger/api/services)"
echo "correct pw : $(curl -s -o /dev/null -w '%{http_code}' -u admin:$PW http://127.0.0.1/select/vmui/)"The first four return 401 and the last returns 200.
A browser that visits the VM without credentials meets the same gate before any part of the interface loads.
Step 7 - Send your first spans over OTLP
The ingest endpoint is /insert/opentelemetry/v1/traces, and it speaks standard OTLP over HTTP. Set Content-Type: application/json to send OTLP/JSON. Set application/x-protobuf to send the binary encoding that most collectors use by default.
This command sends a single span that describes a checkout operation in a service called guide-demo:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt)
TID=$(openssl rand -hex 16);
SID=$(openssl rand -hex 8);
NOW=$(date +%s)
curl -s -o /dev/null -w 'ingest -> HTTP %{http_code}\n' -u admin:$PW \
-H 'Content-Type: application/json' --data-binary "{ \"resourceSpans\": [{ \"resource\": {\"attributes\": [{\"key\": \"service.name\", \"value\": {\"stringValue\": \"guide-demo\"}}]}, \"scopeSpans\": [{\"spans\": [{ \"traceId\": \"$TID\", \"spanId\": \"$SID\", \"name\": \"checkout\", \"kind\": 2, \"startTimeUnixNano\": \"${NOW}000000000\", \"endTimeUnixNano\": \"$((NOW+1))000000000\", \"attributes\": [{\"key\": \"http.response.status_code\", \"value\": {\"intValue\": \"200\"}}] }]}] }] }" http://127.0.0.1/insert/opentelemetry/v1/traces echo "$TID" | sudo tee /tmp/guide-trace-id >/dev/nullA 200 means the span was accepted.
Step 8 - Query your spans back
Spans are not queryable the instant they are accepted. VictoriaTraces buffers incoming spans and flushes them to the searchable store on an interval, typically ten to twenty seconds. Any automation you write should poll instead of assuming the span is immediately visible.
List the services that have reported spans:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt) for i in $(seq 1 30); do
BODY=$(curl -s -u admin:$PW http://127.0.0.1/select/jaeger/api/services) case "$BODY" in *guide-demo*) echo "$BODY"; break ;; esac sleep 3 doneNow fetch the trace itself. The Jaeger API takes start and end as Unix timestamps in microseconds, which is a common source of empty results:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt)
NOW=$(date +%s);
S=$(( (NOW - 3600) * 1000000 ));
E=$(( (NOW + 3600) * 1000000 )) for i in $(seq 1 30); do
BODY=$(curl -s -u admin:$PW "http://127.0.0.1/select/jaeger/api/traces?service=guide-demo&start=$S&end=$E&limit=5") case "$BODY" in *checkout*) break ;; esac sleep 3 done echo "$BODY" | python3 -m json.tool | head -25List the operations a given service has recorded. This shows you what is worth filtering on:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt)
curl -s -u admin:$PW http://127.0.0.1/select/jaeger/api/services/guide-demo/operationsTo fetch one specific trace by id, use the single trace endpoint:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt)
TID=$(sudo cat /tmp/guide-trace-id)
curl -s -u admin:$PW "http://127.0.0.1/select/jaeger/api/traces/$TID" | python3 -m json.tool | head -20Step 9 - Explore traces in the web UI
Open http://<vm-public-ip>/select/vmui/ in a browser and sign in as admin with the password from Step 5. The Traces Explorer shows the spans arriving over time, with a breakdown by operation and service underneath.
The Trace query box filters spans. Because the service name field contains dots and a colon, quote the whole field name. To see only the spans from one service:
"resource_attr:service.name":"checkout-service"Press Execute Query. The chart, the totals and the results below all narrow to that service.
To filter by operation as well, add the span name. This query shows only the place-order spans from checkout-service:
"resource_attr:service.name":"checkout-service" AND name:"place-order"The Table tab lays the matching spans out as rows, which is the quickest way to scan timings across many spans.
The JSON tab shows each span in full, including its duration and every attribute your instrumentation attached. Use it to confirm that the attributes you expect, such as HTTP status codes or database statements, are arriving.
Step 10 - Point an OpenTelemetry Collector at this VM
In production, you will normally send spans through an OpenTelemetry Collector instead of with curl. Add this VM as an OTLP HTTP exporter in your collector configuration. The auth extension supplies the same Basic Auth credentials the API expects:
extensions: basicauth/victoriatraces: client_auth: username: admin password: <VICTORIATRACES_PASSWORD> exporters: otlphttp/victoriatraces: traces_endpoint: http://<vm-public-ip>/insert/opentelemetry/v1/traces auth: authenticator: basicauth/victoriatraces encoding: proto service: extensions: [basicauth/victoriatraces] pipelines: traces: receivers: [otlp] exporters: [otlphttp/victoriatraces]To point an instrumented application straight at the VM, with no collector in between, set the standard OpenTelemetry SDK environment variables. Every OpenTelemetry SDK understands them:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://<vm-public-ip>/insert/opentelemetry/v1/traces OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_TRACES_HEADERS=Authorization=Basic <base64-of-admin:password> OTEL_SERVICE_NAME=my-applicationGenerate the header value for the Authorization header with:
PW=$(sudo sed -n 's/^victoriatraces.password=//p' /root/victoriatraces-credentials.txt) printf 'Authorization=Basic %s\n' "$(printf 'admin:%s' "$PW" | base64 -w0)"Everything travels over plain HTTP by default. Before you send real production spans across a public network, put the VM behind a private network, a VPN or a TLS-terminating load balancer. See Step 13.
Step 11 - Tune retention and size the data disk
Span volume is much higher than log or metric volume, so retention is the setting you are most likely to change. The image ships two limits that work together:
-retentionPeriod=7ddrops spans older than seven days.-retention.maxDiskUsagePercent=80caps the store at 80 percent of the data disk, dropping the oldest partitions first.
The second limit is a safety net. Whatever retention period you choose, a sudden burst of spans cannot fill the volume and wedge the service. Check the current values and how much of the disk is in use:
systemctl show -p ExecStart --value victoriatraces.service | grep -oE '\-retentionPeriod=[^ ]+|\-retention.maxDiskUsagePercent=[^ ]+' df -h /var/lib/victoria-traces du -sh /var/lib/victoria-traces 2>/dev/null || trueTo change the retention period, edit the systemd unit and restart the service:
sudo systemctl edit --full victoriatraces.service
# change -retentionPeriod=7d to e.g. 30d
sudo systemctl daemon-reload
sudo systemctl restart victoriatraces.serviceSizing the disk. Storage need scales with spans per second and retention, not with the number of services. As a planning starting point, VictoriaTraces stores a typical span in well under a kilobyte after compression, so the need is roughly spans per second x 86400 x retention days x span size. At 100 spans per second and 7 days, that is on the order of a few gigabytes, which the 32 GiB default disk holds comfortably.
If you raise retention to 30 days or push several hundred spans per second, grow the data disk in the Azure portal and then extend the filesystem. Watch the actual growth rate over your first few days with du -sh, and size from your own measured numbers instead of an estimate.
Step 12 - Verify the appliance at any time
The image ships a self test that re-proves everything this guide has covered. It checks that the health probe is open and that unauthenticated ingest and unauthenticated queries are both rejected. It checks that a wrong password is rejected. It also checks that a real span sent over OTLP comes back through the Jaeger query API with its operation name and attributes intact. Run it:
sudo /usr/local/sbin/victoriatraces-selftest.shOn success, the test prints a single OK- line. Otherwise, it prints a SELFTEST-FAIL: line that names the failing check. It is a useful smoke test after you change the nginx configuration, rotate the password or resize the disk.
A note on the spans it leaves behind. The image itself ships with a completely empty trace store. However, this self test runs once automatically during first boot to prove that the appliance works before you rely on it, and each run ingests one real span. The first time you open the UI, you will see a service named sac-selftest-<timestamp> alongside your own. Another appears each time you run the self test by hand.
These spans are harmless. They are the proof that the round trip worked, and they disappear on their own once they pass the retention period. To start from a completely clean store, stop the service, clear the storage directory and start it again, before you point any application at the VM:
sudo systemctl stop victoriatraces
sudo find /var/lib/victoria-traces -mindepth 1 -maxdepth 1 ! -name lost+found -exec rm -rf {} +
sudo systemctl start victoriatracesStep 13 - Production hardening
- Add TLS. Spans and credentials travel in clear text over HTTP. Put the VM behind an Azure Application Gateway or Load Balancer that terminates TLS, or add a certificate to nginx directly and open port 443. The image does not ship a certificate because it cannot know your domain.
- Restrict the network. Tracing backends should stay private to your own infrastructure. Scope the network security group for port 80 to the subnets your applications and collectors run in, instead of leaving it open to the internet.
- Rotate the password. Replace the generated password by writing a new bcrypt entry. Then update the credentials note so the self test and your collectors stay in sync:
sudo htpasswd -B /etc/nginx/.victoriatraces.htpasswd admin
sudo systemctl reload nginx- Back up what matters. Spans are usually reproducible and short-lived, so most teams do not back up a trace store. If yours is an exception, snapshot the data disk instead of copying files out from under a running service.
- Keep the OS patched. Unattended security upgrades are enabled by default. Leave them on.
Troubleshooting
A query returns an empty result immediately after ingesting. This is the flush interval, not an error. Spans become searchable roughly ten to twenty seconds after they are accepted. Poll as shown in Step 8 instead of querying once.
A Jaeger query returns nothing even after waiting. Check the start and end parameters. They are Unix timestamps in microseconds, not milliseconds or seconds. A window in the wrong unit silently matches nothing.
The UI query box returns no results for a service you know exists. Quote the whole field name: "resource_attr:service.name":"checkout-service". Leaving it unquoted is a parse error, because the field name itself contains a colon and dots.
Your collector gets 401. The credentials cover the ingest path as well as the query paths. Confirm the exporter is sending Basic Auth and that the password matches /root/victoriatraces-credentials.txt.
There is a sac-selftest-... service you did not create. That is the first-boot self test described in Step 12, not stray build data. See that step for what it is and how to clear it.
The service will not start. Check the journal and confirm that the data disk is mounted, because VictoriaTraces will not start if its storage path is missing:
systemctl status victoriatraces.service --no-pager | tail -20 mountpoint /var/lib/victoria-traces && echo "data disk mounted"Support
SecureAnyCloud provides 24/7 support for this image. Contact sales@secureanycloud.com.
Deploy on Azure
Launch VictoriaTraces 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
VictoriaTraces is an OpenTelemetry-compatible distributed tracing database from the VictoriaMetrics family. It accepts trace spans over the standard OTLP HTTP protocol and serves them back through Jaeger-compatible query APIs and a built-in browser interface. It does this from a single static Go binary with no external storage dependency. There is no Cassandra, no Elasticsearch and no object store to operate.
This image installs the VictoriaTraces binary at /usr/local/bin/victoria-traces-prod. It runs as a dedicated, unprivileged victoriatraces system account under a systemd service that starts it on boot and restarts it on failure. Stored spans live at /var/lib/victoria-traces, which is a dedicated, independently resizable EBS data volume.
VictoriaTraces ships with no built-in authentication of any kind. For a tracing backend, that matters twice over. An open ingest endpoint lets anyone write or poison the trace store, and an open query endpoint leaks every span in it, including hostnames, URLs, user identifiers and the topology of your services.
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 OTLP ingest path and the Jaeger query APIs 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/victoriatraces-credentials.txt with mode 0600, so only the root user can read it.
Project Maturity
VictoriaTraces is a newer component of the VictoriaMetrics family, first released in July 2025 and under active development. It is pre-general availability by the project's own statement. Upstream has not yet committed to backward compatibility for the on-disk data format, so a future major upgrade may require re-ingesting spans instead of upgrading in place. Plan your adoption accordingly.
The software itself is Apache 2.0 licensed and is installed unmodified from the official upstream release.
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 OTLP ingest path and the query APIs.
- 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 VictoriaTraces. Select the SecureAnyCloud 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. 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 following block launches an instance from the SecureAnyCloud VictoriaTraces 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 in Prerequisites.
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=victoriatraces}]'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.
Connect to Your Instance
Connect over SSH using your key pair and the login user for your operating system variant. For Ubuntu 24.04, the 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. Keep it out of shell history and out of shared terminals.
sudo cat /root/victoriatraces-credentials.txtThe file records the web interface URL, the OTLP 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 that the credentials file is present and correctly locked down, without printing its contents:
sudo test -f /root/victoriatraces-credentials.txt && echo "credentials file present"
sudo stat -c '%a %U:%G' /root/victoriatraces-credentials.txt
sudo grep -c '^victoriatraces.password=' /root/victoriatraces-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 Traces Explorer opens with a query bar, a volume histogram and the matching spans grouped by stream.
Enter a query in the Trace query box and select Execute Query to filter the stored spans. Because the OpenTelemetry resource attribute name contains a colon, quote the field name. This query returns every span that belongs to a single service:
"resource_attr:service.name":"checkout-api"The Table tab renders the same result set as a column view, which is the quickest way to scan span timings and stream labels side by side.
The JSON tab shows the full stored record for each span, including its trace and span identifiers, its duration in nanoseconds, and every resource and span attribute your instrumentation attached.
Confirm VictoriaTraces Is Running
Check that both services are active and that the database is listening on the loopback interface only:
systemctl is-active victoriatraces.service
systemctl is-active nginx.service ss -tln | awk '{print $4}' | grep -c '127.0.0.1:10428' 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 directly and it deliberately needs no credentials, so load balancer and target group health checks work without embedding a password.
Confirm that 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:10428$|^\*:10428$|^\[::\]:10428$)' || trueThe count must be 0. Everything from outside the instance goes through nginx on port 80.
Confirm the Authentication Gate
Both halves of the appliance, span ingestion and span querying, sit behind the same HTTP Basic authentication gate. Verify that unauthenticated access is refused and that the generated password is accepted. The commands read the password into a shell variable and never print it.
PW=$(sudo sed -n 's/^victoriatraces\.password=//p' /root/victoriatraces-credentials.txt)
curl -s -o /dev/null -w 'unauthenticated query: HTTP %{http_code}\n' http://127.0.0.1/select/jaeger/api/services
curl -s -o /dev/null -w 'unauthenticated ingest: HTTP %{http_code}\n' -X POST -H 'Content-Type: application/json' --data-binary '{}' http://127.0.0.1/insert/opentelemetry/v1/traces
curl -s -o /dev/null -w 'wrong password: HTTP %{http_code}\n' -u 'admin:not-the-password' http://127.0.0.1/select/jaeger/api/services
curl -s -o /dev/null -w 'correct password: HTTP %{http_code}\n' -u "admin:$PW" http://127.0.0.1/select/jaeger/api/servicesThe first three must return HTTP 401 and the last must return HTTP 200.
Send Spans over OpenTelemetry OTLP
Point any OpenTelemetry SDK or an OpenTelemetry Collector at the instance's OTLP HTTP endpoint, using the same HTTP Basic credentials. The endpoint accepts protobuf or JSON, selected by the Content-Type header.
The block below sends one complete span and then reads it back through the Jaeger-compatible query API. This proves the full ingest-to-query round trip on your own instance.
PW=$(sudo sed -n 's/^victoriatraces\.password=//p' /root/victoriatraces-credentials.txt) SVC="guide-demo-$(date +%s)"
TID=$(openssl rand -hex 16);
SID=$(openssl rand -hex 8)
S=$(date +%s);
E=$((S + 1)) curl -s -o /dev/null -w 'ingest: HTTP %{http_code}\n' -u "admin:$PW" \
-H 'Content-Type: application/json' \
--data-binary "{\"resourceSpans\":[{\"resource\":{\"attributes\":[{\"key\":\"service.name\",\"value\":{\"stringValue\":\"$SVC\"}}]},\"scopeSpans\":[{\"scope\":{\"name\":\"guide\"},\"spans\":[{\"traceId\":\"$TID\",\"spanId\":\"$SID\",\"name\":\"guide-demo-span\",\"kind\":2,\"startTimeUnixNano\":\"${S}000000000\",\"endTimeUnixNano\":\"${E}000000000\",\"status\":{}}]}]}]}" \
http://127.0.0.1/insert/opentelemetry/v1/traces
QS=$(( (S - 3600) * 1000000 ));
QE=$(( (E + 3600) * 1000000 )) FOUND=no for _ in $(seq 1 20); do
BODY=$(curl -s -u "admin:$PW" "http://127.0.0.1/select/jaeger/api/traces?service=$SVC&start=$QS&end=$QE&limit=20") case "$BODY" in *"$TID"*) FOUND=yes; break ;; esac sleep 2 done echo "round trip: span $TID returned by the Jaeger query API: $FOUND" [ "$FOUND" = yes ]The ingest must report HTTP 200 and the round trip line must end in yes, meaning the exact span you sent was stored and read back. A newly ingested span becomes queryable within a few seconds, and the loop above allows up to 40. Each run uses a fresh service name, so the assertion stays exact however many spans the instance already holds.
To point an OpenTelemetry Collector at this instance, use an OTLP HTTP exporter with basic authentication. Replace the sample values with your instance address and generated password:
exporters: otlphttp: endpoint: http://<public-ip> traces_endpoint: http://<public-ip>/insert/opentelemetry/v1/traces auth: authenticator: basicauth/traces extensions: basicauth/traces: client_auth: username: admin password: <your-password>Query Traces with the Jaeger Compatible APIs
VictoriaTraces exposes Jaeger-compatible query endpoints, so existing Jaeger tooling and Grafana's Jaeger data source can read from it. List the services that have reported spans, and the operations recorded for one of them:
PW=$(sudo sed -n 's/^victoriatraces\.password=//p' /root/victoriatraces-credentials.txt)
curl -s -u "admin:$PW" http://127.0.0.1/select/jaeger/api/services | head -c 400 echo
SVC=$(curl -s -u "admin:$PW" http://127.0.0.1/select/jaeger/api/services \
| python3 -c 'import json,sys; d=json.load(sys.stdin)["data"] or ["none"]; print(d[0])')
echo "inspecting operations for service: $SVC" curl -s -o /dev/null -w 'operations API: HTTP %{http_code}\n' -u "admin:$PW" \
"http://127.0.0.1/select/jaeger/api/services/$SVC/operations"To connect Grafana, add a Jaeger data source with the URL http://<public-ip>/select/jaeger and enable Basic auth with the username admin and your generated password.
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 and the negative controls (unauthenticated ingest refused, unauthenticated query refused, wrong password refused). It also runs a full OTLP ingest-to-Jaeger-query round trip that reads the exact span back with its operation name and span attribute.
sudo /usr/local/sbin/victoriatraces-selftest.shIt prints a single OK-otlp-ingest-to-jaeger-query-roundtrip-and-basic-auth-gate-proven line on success and exits non-zero on any failure.
The Data Volume
Stored spans live on a dedicated EBS volume mounted at /var/lib/victoria-traces, separate from the operating system disk and independently resizable. /etc/fstab references it by filesystem UUID, so it remounts correctly on every boot regardless of NVMe device naming.
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/victoria-traces df -h /var/lib/victoria-traces | tail -1 grep -c 'victoria-traces' /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 VictoriaTraces configuration changes are needed.
Retention and Disk Sizing
Span retention defaults to 7 days. Storage is additionally capped at 80 percent of the data volume, so a burst of spans can never fill the disk and wedge the service. VictoriaTraces drops the oldest partitions first. Both settings are single flags on the service unit:
systemctl cat victoriatraces.service | grep -E 'retentionPeriod|maxDiskUsagePercent|storageDataPath'To change them, override the unit with sudo systemctl edit victoriatraces.service and supply a replacement ExecStart with your preferred values. Then reload and restart the service. Trace volume is typically far higher than log volume, so size the data volume against your actual span rate, not your log rate.
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 OpenTelemetry exporters to the https:// endpoint.
Backup and Maintenance
The span store is at /var/lib/victoria-traces. 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.
Update operating system packages with the distribution's normal tooling. To move to a newer VictoriaTraces release, replace the binary at /usr/local/bin/victoria-traces-prod with the official upstream build and restart the service. The project has not yet committed to on-disk format compatibility, so read the upstream release notes before any major version upgrade.
Check service health and recent activity at any time:
systemctl is-active victoriatraces.service nginx.service curl -s -o /dev/null -w 'healthz: HTTP %{http_code}\n' http://127.0.0.1/healthzSupport
SecureAnyCloud publishes and supports this image. Technical support is available 24 hours a day, 7 days a week by email at sales@secureanycloud.com.
Support covers deployment and instance sizing, OpenTelemetry Collector and SDK configuration against the OTLP endpoint, retention and disk sizing, TLS termination, nginx and authentication configuration, VictoriaTraces version upgrades, and troubleshooting ingestion, query and connectivity issues. Include your instance ID and AWS Region when you get in touch, so that we can help faster.
VictoriaTraces and VictoriaMetrics are trademarks of their respective owners. SecureAnyCloud is not affiliated with or endorsed by VictoriaMetrics.
Deploy on AWS
Launch VictoriaTraces on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com