DockerSelf-Hosting

VictoriaMetrics with Docker: Lightweight Prometheus-Compatible Monitoring with Grafana (Linux, Windows, Mac)

Before you start

  • 21 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

VictoriaMetrics is a free, open-source time series database that speaks the Prometheus language: you point your scrapers or Grafana at it and keep months of metrics in one small container.

VictoriaMetrics official logo

Logo: the official VictoriaMetrics project (github.com/VictoriaMetrics/VictoriaMetrics)

It suits a home lab or small server where Prometheus uses more memory and disk than you like. The single-node version is one process with no dependencies, set up with command-line flags. It scrapes Prometheus-style targets itself and can also be long-term storage behind a Prometheus you already run.

WhatValue (official docs and registries, read October 2026)
Current versionVictoriaMetrics v1.155.0, released October 2026 (latest release)
Images to pinvictoriametrics/victoria-metrics:v1.155.0 and grafana/grafana:13.3.0 (both tags checked on Docker Hub)
Time neededAbout 20 minutes plus image downloads (our estimate; Grafana is about 0.5 GB to pull)
Size and RAMMeasured on Windows, idle: VictoriaMetrics 156 MiB RAM, Grafana 260 MiB; VictoriaMetrics image 57 MB on disk
PortsTCP 8428 (VictoriaMetrics and its vmui page), TCP 3000 (Grafana); both published on 127.0.0.1 here
LicenceApache-2.0 (LICENSE at the release tag); paid enterprise features exist separately
Official docsdocs.victoriametrics.com and the repository

At a glance:

  • What it is: one binary that stores metrics, answers PromQL-style queries and has a built-in web page called vmui.
  • What you build: VictoriaMetrics plus Grafana in one Compose file, with a scrape file for your computer's own numbers.
  • The flag to know: -retentionPeriod. The default is one month, and a bare number means months, not days.
  • Single-node or cluster: the docs say to try single-node first. This guide uses it.
  • Backups: the official vmbackup tool works from instant snapshots without stopping anything.
  • Not internet-safe by default: the docs say to keep it in private networks. Only Grafana goes behind HTTPS here.

How it fits together#

VictoriaMetrics pulls numbers from exporters, keeps them in a folder on your disk, and Grafana asks it questions when you open a dashboard.

Two-lane diagram: VictoriaMetrics on port 8428 scrapes an exporter on your computer every 15 seconds and writes to a data folder on the host, from which vmbackup takes snapshots; you open Grafana on port 3000 in a browser, optionally through Caddy or Traefik with HTTPS, and Grafana sends PromQL queries to VictoriaMetrics

Drawn for this guide from the official docs and our Compose file. The dashed parts are optional.

Before you start#

You need a computer that runs Docker and Docker Compose. The same Compose file works on Linux, Windows and Mac.

SystemWhat you need
LinuxDocker Engine with Compose v2, any x86_64 or arm64 machine, about 1 GB of free RAM and a few GB of disk
WindowsDocker Desktop (WSL 2 backend), PowerShell, an administrator account for the exporter in Step 4
MacDocker Desktop, Terminal, Homebrew for the exporter in Step 4

Check Docker on every system:

Run in terminalbash
docker --version
docker compose version

Checklist:

  • [ ] Ports 8428 and 3000 are free on your computer
  • [ ] You have backed up any existing ~/docker_volumes/victoriametrics folder
  • [ ] For the HTTPS section only: a domain with a DNS record for the server, and ports 80 and 443 free

Tested on 2026-10-31: Linux = not run, Windows = Steps 1 to 3 and the backup and restore test (Windows 11 with Docker Desktop), Mac = not run. The exporters in Step 4 and the HTTPS route were not run. Everything else comes from the official docs read in October 2026.

Step 1: Create the folders and config files#

All data lives in ~/docker_volumes/victoriametrics. You create three small config files and one .env file.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/victoriametrics/{data/vm,data/grafana,config,backups}
cd ~/docker_volumes/victoriametrics

cat > config/scrape.yml << 'EOF'
scrape_configs:
  - job_name: host
    scrape_interval: 15s
    static_configs:
      - targets: ["host.docker.internal:9100"]
EOF

cat > config/grafana-datasource.yml << 'EOF'
apiVersion: 1

datasources:
  - name: VictoriaMetrics
    type: prometheus
    access: proxy
    url: http://victoriametrics:8428
    isDefault: true
    jsonData:
      prometheusType: Prometheus
      prometheusVersion: 2.24.0
EOF

printf 'GRAFANA_ADMIN_PASSWORD=%s\nGRAFANA_UID=%s\n' "$(openssl rand -hex 16)" "$(id -u)" > .env
chmod 600 .env

Windows (PowerShell)#

Codepowershell
$d = "$HOME\docker_volumes\victoriametrics"
New-Item -ItemType Directory -Force "$d\data\vm","$d\data\grafana","$d\config","$d\backups" | Out-Null
Set-Location $d

@'
scrape_configs:
  - job_name: host
    scrape_interval: 15s
    static_configs:
      - targets: ["host.docker.internal:9182"]
'@ | Set-Content -Encoding utf8 config\scrape.yml

@'
apiVersion: 1

datasources:
  - name: VictoriaMetrics
    type: prometheus
    access: proxy
    url: http://victoriametrics:8428
    isDefault: true
    jsonData:
      prometheusType: Prometheus
      prometheusVersion: 2.24.0
'@ | Set-Content -Encoding utf8 config\grafana-datasource.yml

$pw = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object { [char]$_ })
"GRAFANA_ADMIN_PASSWORD=$pw" | Set-Content -Encoding ascii .env

Mac (Terminal)#

Same commands as Linux, run in Terminal. The scrape target host.docker.internal:9100 is resolved by Docker Desktop to your Mac.

The datasource file is the one in the official Compose environment (deployment/docker/provisioning/datasources/prometheus/single.yml), with the same Prometheus type and version 2.24.0 that the Grafana integration page asks for. The scrape file points at an exporter on your computer; Step 4 starts it. Until then, VictoriaMetrics logs connection refused for that target. That is expected.

Check it worked. The folder holds config, data, backups and .env:

Run in terminalbash
ls -A ~/docker_volumes/victoriametrics

On Windows, use Get-ChildItem -Force.

Tip: The Grafana admin password is the line in .env. Read it with cat .env (Windows: Get-Content .env) and store it in a password manager.

Step 2: Write the Compose file and start everything#

One file for all three systems. It pins both images, keeps both web ports on 127.0.0.1, and adds vmbackup as an on-demand service that starts only when you ask for it.

File contentyaml
services:
  victoriametrics:
    image: victoriametrics/victoria-metrics:v1.155.0
    container_name: victoriametrics
    restart: unless-stopped
    command:
      - "-storageDataPath=/storage"
      - "-retentionPeriod=90d"
      - "-selfScrapeInterval=10s"
      - "-promscrape.config=/config/scrape.yml"
    ports:
      - "127.0.0.1:8428:8428"
    volumes:
      - ./data/vm:/storage
      - ./config:/config:ro
    extra_hosts:
      - "host.docker.internal:host-gateway"

  grafana:
    image: grafana/grafana:13.3.0
    container_name: grafana
    restart: unless-stopped
    user: "${GRAFANA_UID:-472}"
    depends_on:
      - victoriametrics
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
    volumes:
      - ./data/grafana:/var/lib/grafana
      - ./config/grafana-datasource.yml:/etc/grafana/provisioning/datasources/victoriametrics.yml:ro

  vmbackup:
    image: victoriametrics/vmbackup:v1.155.0
    profiles: ["backup"]
    depends_on:
      - victoriametrics
    volumes:
      - ./data/vm:/storage
      - ./backups:/backups

The flags, from the flag list: -storageDataPath is the data folder inside the container; -retentionPeriod=90d keeps 90 days; -selfScrapeInterval=10s records VictoriaMetrics' own metrics so you see data at once; -promscrape.config is the scrape file. host-gateway is Docker's special value for "the host", so a container can reach exporters on your computer.

Linux#

Save the file as ~/docker_volumes/victoriametrics/docker-compose.yml (for example with nano docker-compose.yml), then:

Run in terminalbash
cd ~/docker_volumes/victoriametrics
docker compose config -q
docker compose up -d
docker compose ps

Windows (PowerShell)#

Save the file as docker-compose.yml in $HOME\docker_volumes\victoriametrics (for example with notepad docker-compose.yml), then:

Codepowershell
Set-Location "$HOME\docker_volumes\victoriametrics"
docker compose config -q
docker compose up -d
docker compose ps

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
cd ~/docker_volumes/victoriametrics
docker compose config -q
docker compose up -d
docker compose ps

Check it worked. docker compose ps shows victoriametrics and grafana as Up. The VictoriaMetrics log (docker compose logs victoriametrics --tail 40) contains these lines (real output from our Windows test, shortened):

Codetext
-retentionPeriod="90d"
opening storage at "/storage" with -retentionPeriod=90d
started VictoriaMetrics in 1.032 seconds
started self-scraping `/metrics` page with interval 10.000 seconds
started server at http://0.0.0.0:8428/

Tip: Run docker compose config -q before every up. It prints nothing when the file is valid and names the broken line when it is not.

Step 3: Look at your first numbers#

VictoriaMetrics records its own metrics, so you have something to see before any exporter runs. Self-scraped metrics become queryable about 30 seconds after the start (Quick-Start).

Linux#

Run in terminalbash
curl -s "http://127.0.0.1:8428/api/v1/query?query=vm_app_version"
xdg-open http://localhost:8428/vmui

Windows (PowerShell)#

Run in terminalpowershell
curl.exe -s "http://127.0.0.1:8428/api/v1/query?query=vm_app_version"
Start-Process http://localhost:8428/vmui

Mac (Terminal)#

Run in terminalbash
curl -s "http://127.0.0.1:8428/api/v1/query?query=vm_app_version"
open http://localhost:8428/vmui

Check it worked. The query returns JSON with "short_version":"v1.155.0" (real output from our test, shortened):

File contenttext
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"vm_app_version","instance":"self","job":"victoria-metrics","short_version":"v1.155.0",...},"value":[...,"1"]}]},...}

In vmui, type process_resident_memory_bytes and press Enter: you see how much memory VictoriaMetrics uses. Then open http://localhost:3000 and log in as admin with the password from .env. Under Connections, then Data sources, the entry VictoriaMetrics is already there, created from your datasource file. In our test it showed as read-only, which is normal for provisioned sources.

Tip: Grafana reads GRAFANA_ADMIN_PASSWORD only on its first start. Grafana's docs say the admin password is "set once on first-run". To change it later, use the profile page in Grafana, not the .env file.

Step 4: Scrape your own computer#

An exporter is a small program that publishes your computer's numbers (CPU, memory, disk, network) on a web page. VictoriaMetrics pulls that page every 15 seconds, using the scrape file from Step 1.

Linux#

Add the official node_exporter as a container. The README says a containerized exporter needs host networking, the host process list and the root filesystem mounted read-only. Add this under services: in your docker-compose.yml:

File contentyaml
  node-exporter:
    image: quay.io/prometheus/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    command:
      - "--path.rootfs=/host"
    network_mode: host
    pid: host
    volumes:
      - "/:/host:ro,rslave"
Run in terminalbash
docker compose up -d
curl -s http://127.0.0.1:9100/metrics | head -3

Windows (PowerShell)#

Install windows_exporter v0.32.1 from an administrator PowerShell. The README's command creates a firewall exception, which a container needs to reach it. It listens on port 9182.

Codepowershell
$msi = "$env:TEMP\windows_exporter-0.32.1-amd64.msi"
Invoke-WebRequest "https://github.com/prometheus-community/windows_exporter/releases/download/v0.32.1/windows_exporter-0.32.1-amd64.msi" -OutFile $msi
msiexec /i $msi --% ADDLOCAL=FirewallException
curl.exe -s http://localhost:9182/metrics | Select-Object -First 3

Mac (Terminal)#

Install node_exporter with Homebrew (the formula is at 1.12.1) and run it as a service on port 9100:

Run in terminalbash
brew install node_exporter
brew services start node_exporter
curl -s http://127.0.0.1:9100/metrics | head -3

Check it worked. Open http://localhost:8428/targets. The host job should show 1/1 up. Before the exporter ran, our Windows test showed job=host (0/1 up) and this log line, which is the sign that the exporter is missing, not that VictoriaMetrics is broken:

Run in terminaltext
cannot scrape target "http://host.docker.internal:9182/metrics" ... connect: connection refused

Then query node_memory_MemAvailable_bytes in vmui (Linux and Mac). For the Windows exporter, open vmui's metrics explorer at http://localhost:8428/vmui/#/metrics and browse the names that start with windows_.

Tip: On Docker Desktop, a node_exporter container reports the small Linux virtual machine behind Docker, not your PC. That is why Windows and Mac use an exporter installed on the computer itself.

Step 5: Add a dashboard in Grafana#

The VictoriaMetrics team publishes a ready dashboard on grafana.com: "VictoriaMetrics - single-node", ID 10229 (updated October 2026). It shows ingestion, memory, disk and slow queries.

Linux#

In Grafana, open Dashboards, then New, then Import, enter 10229, press Load, choose the VictoriaMetrics data source and import.

Windows (PowerShell)#

The same clicks in the browser. Nothing to type in PowerShell.

Mac (Terminal)#

The same clicks in the browser.

Check it worked. The dashboard shows panels with data. We imported it through Grafana's API in our Windows test and it was accepted; we did not look at the panels in a browser. For your computer's own numbers, the third-party dashboard "Node Exporter Full" (ID 1860) targets node_exporter; read its page first.

Tip: Pick the data source in the dashboard's top bar (the ds variable) if panels say "No data". Wait a minute after the first start as well.

Single-node or cluster?#

Start with single-node. The cluster docs say so themselves: use the single-node version for ingestion below about a million data points per second, because it is easier to run and scales with CPU, RAM and disk.

Single-node (this guide)Cluster
PartsOne processvminsert, vmselect, vmstorage
Good forHome labs, small and mid-size teamsNeeds beyond one machine; replication; several tenants
EffortOne container, flagsMore services, more network traffic
Moving laterData must be re-ingested into a cluster-

Single-node data cannot be moved into vmstorage without re-ingesting it, and backups of one cannot be restored into the other.

Retention and disk space#

-retentionPeriod takes a number and a unit: h, d, w, M (month) or y. Examples: 90d, 6M, 1y. A bare number means months: -retentionPeriod=3 keeps 93 days. The default is one month and the minimum is one day.

  • Data is stored in monthly partitions. A partition outside the retention is deleted on the first day of the new month, so the disk can hold up to retention plus one month.
  • You can raise retention at any time. Lowering it deletes old data in the background.
  • There is no "keep forever"; the docs suggest a high value such as 100y.
  • Plan the disk by measuring: 10 GB after a one-day test means about 1 TB for 100 days.
  • Keep at least 20% of the disk free. Below -storage.minFreeDiskSpaceBytes (default 100000000 bytes) VictoriaMetrics goes read-only and refuses new data.

To change the flag, edit -retentionPeriod in docker-compose.yml and run docker compose up -d. Flags only change on restart.

If you already run Prometheus#

Two routes, both from the docs. VictoriaMetrics can scrape your existing prometheus.yml itself: pass it as -promscrape.config (for unsupported options, remove them or add -promscrape.config.strictParse=false). Or keep Prometheus and add remote write to its config:

File contentyaml
remote_write:
  - url: http://<victoriametrics-addr>:8428/api/v1/write

Remote write can raise Prometheus memory use by about 25% (docs). For Prometheus itself, see our Docker container monitoring with Prometheus and Grafana guide. For a simpler server monitor, try Beszel or Uptime Kuma 2.

Put it behind HTTPS (with or without Traefik)#

Only Grafana needs HTTPS. Keep VictoriaMetrics on 127.0.0.1: the docs say its components belong in private networks, and port 8428 has no login by default. Local-only users can skip this section. Both routes need a domain with a DNS record for the server. The commands are the same on Linux, Windows (Docker Desktop) and Mac; only the folder style differs.

With Traefik#

On a server that already runs Traefik v3 with the Docker provider, put Grafana on the proxy network and add labels. Create the network once if it is missing:

Run in terminalbash
docker network create proxy

Replace the grafana service in docker-compose.yml and add the networks block at the bottom. The host port is gone, and Grafana learns its public address through GF_SERVER_ROOT_URL (the root_url setting, which Grafana's docs say matters behind a proxy):

File contentyaml
  grafana:
    image: grafana/grafana:13.3.0
    container_name: grafana
    restart: unless-stopped
    user: "${GRAFANA_UID:-472}"
    depends_on:
      - victoriametrics
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_SERVER_ROOT_URL=https://grafana.<your-domain>/
    volumes:
      - ./data/grafana:/var/lib/grafana
      - ./config/grafana-datasource.yml:/etc/grafana/provisioning/datasources/victoriametrics.yml:ro
    networks:
      - default
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.grafana.rule=Host(`grafana.<your-domain>`)"
      - "traefik.http.routers.grafana.entrypoints=https"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.services.grafana.loadbalancer.server.port=3000"

networks:
  proxy:
    external: true

Use your own entrypoint name if it is not https. Then run docker compose up -d.

Check it worked. curl -I https://grafana.<your-domain>/ returns an HTTP status line over HTTPS, and Grafana opens with a valid certificate.

Without Traefik: Caddy#

Choose this if you have no Traefik. Caddy gets and renews its own certificates. Caddy's docs describe automatic Let's Encrypt certificates for a public domain and tls internal, its own local certificate authority, for a home name.

Use the same Grafana service as in the Traefik block but without the labels: lines. Then create the Caddy folder and file (Windows: $HOME\docker_volumes\caddy):

Run in terminalbash
mkdir -p ~/docker_volumes/caddy/{data,config}
cd ~/docker_volumes/caddy
File contentyaml
services:
  caddy:
    image: caddy:2.11.7
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config
    networks:
      - proxy

networks:
  proxy:
    external: true

The Caddyfile for a public domain:

File contenttext
grafana.example.com {
    reverse_proxy grafana:3000
}

For a home-only name, use tls internal:

File contenttext
grafana.home.arpa {
    tls internal
    reverse_proxy grafana:3000
}

Start both stacks (docker compose up -d in each folder). For tls internal, each device must trust Caddy's root certificate. Caddy's command-line docs say its caddy trust command installs the root into the local trust store; with Docker you copy it out instead:

Run in terminalbash
docker exec caddy find /data -name root.crt
docker cp caddy:<path-from-find> ./caddy-root.crt

Install caddy-root.crt as a trusted root on each device. These OS steps are not from the Caddy docs: Windows, "Trusted Root Certification Authorities"; macOS, Keychain Access with "Always Trust"; Linux, your distribution's CA store.

Check it worked. curl -I https://grafana.example.com/ returns a status line. For a home name, the browser shows a padlock only after the root is trusted.

Tip: A certificate error usually means the name in the Caddyfile differs from the DNS record, or ports 80 and 443 do not reach Caddy.

Security and testing#

ControlHow
PortsKeep 127.0.0.1:8428 and 127.0.0.1:3000. Never forward 8428 on your router.
Login for VictoriaMetricsNone by default. If other machines must reach it, use -httpAuth.username and -httpAuth.password, or the vmauth proxy the docs recommend, behind HTTPS.
Admin endpointsProtect snapshots and series deletion with -snapshotAuthKey and -deleteAuthKey (docs); limit /metrics to trusted networks.
Exporter ports9100 and 9182 are open to your network once the exporter runs. Do not forward them.
Secrets.env is chmod 600 on Linux and Mac. Do not commit it.
BackupsThey contain all your metrics. Keep backups/ out of shared folders.

Quick tests after any change:

Run in terminalbash
docker compose ps
docker compose logs --tail=100 victoriametrics
curl -s "http://127.0.0.1:8428/api/v1/query?query=up"

On Windows use curl.exe. A healthy setup answers "status":"success".

Common mistakes#

These come from the issue tracker, the docs' warnings, our test run and common AI assistant answers.

MistakeWhy it happensDo this instead
Writing -retentionPeriod=12 and expecting 12 daysA bare number means months. Issue #10181 (closed) was opened because the unit-less form is confusingAlways write the unit: 12M, 90d, 1y
Forgetting the retention flagThe default is one month and older data is deleted for good. Issue #9751 (closed) calls this a data-loss trapSet -retentionPeriod in the first Compose file you write
Running vmbackup without mounting the data foldervmbackup looks for the snapshot at its own -storageDataPath. Issue #8739 (closed) shows cannot open snapshot at "vmdata/snapshots/..."Mount the same ./data/vm into the backup container, as the vmbackup service here does
Not mounting the backup destinationThe backup then goes into the container's own disk and disappears. Same issue #8739Mount ./backups and write to fs:///backups/...
Typing vmbackup or vmrestore flags unquoted in PowerShellPowerShell splits -snapshot.createURL=... at the dot. Our test returned flag provided but not defined: -snapshotQuote every flag: "-snapshot.createURL=http://..."
Copying data/vm/snapshots with cp or rsyncSnapshots are hard links, so a plain copy can miss data (docs)Use vmbackup
Letting the disk fill upBelow -storage.minFreeDiskSpaceBytes VictoriaMetrics turns read-only and stops accepting new dataKeep 20% free, and watch disk use in the dashboard
Using a retention of a few days and expecting a small diskIndex data is kept in monthly partitions. Issue #10961 (closed) reports more disk than expected below one monthMeasure the folder size after a week; plan for the monthly cycle
Publishing 8428 on all interfacesThe Quick-Start docker run publishes -p 8428:8428, which listens everywherePublish 127.0.0.1:8428:8428 and add a login before sharing it
Setting the Grafana password in .env after the first startGrafana reads admin_password only on first runChange it in Grafana's profile page
AI assistants: giving Prometheus flags such as --storage.tsdb.retention.time or --config.fileVictoriaMetrics has its own flags; the Go flag parser stops with flag provided but not defined, as in our vmbackup testUse -retentionPeriod and -promscrape.config; check names with -help
AI assistants: pointing Grafana at port 9090 or 8429, or using latest9090 is Prometheus and 8429 is vmagent. The single-node port is 8428Use http://victoriametrics:8428 and pin v1.155.0

Tip: When an assistant gives you a VictoriaMetrics command, compare every flag with docker run --rm victoriametrics/victoria-metrics:v1.155.0 -help. It prints the real list.

Tip: Take a backup before every upgrade and read the release notes first.

Troubleshooting#

ProblemSolution
flag provided but not defined: -snapshotPowerShell split the flag. Put quotes around each flag, as in the backup step
Target host shows 0/1 up and the log says connection refusedThe exporter is not running or not reachable. Start it (Step 4) and allow its port in the firewall; on Linux, a host firewall such as ufw can block the Docker network
Grafana shows "No data"Check the data source URL is http://victoriametrics:8428, wait 30 seconds after a start, and run up in vmui
Grafana will not start on Linux and the log shows a permission errorThe container user must be able to write data/grafana. Set GRAFANA_UID=$(id -u) in .env (Grafana's bind-mount docs)
Port 8428 or 3000 already in useChange the left number in ports: (for example 127.0.0.1:18428:8428)
VictoriaMetrics logs cannot read process_io_* metrics from "/proc/self/io"We saw this once on Docker Desktop for Windows; the process kept running. The docs do not explain it
No data after you lowered retentionData outside the new period is deleted in the background, not at once

cannot fallocate ... operation not supported#

Our Windows test showed this when vmrestore wrote into a folder bind-mounted from the Windows disk:

Run in terminaltext
cannot restore from backup: cannot preallocate data/indexdb/2026_10/parts.json: cannot fallocate 210 bytes for "/restore/data/indexdb/2026_10/parts.json.tmp": operation not supported

Restore into a named Docker volume instead (see the restore test below). On Mac with Docker Desktop we did not test; use a volume if you see the same text.

cannot open snapshot at "vmdata/snapshots/..."#

The backup container cannot see the data folder. Mount ./data/vm into it (issue #8739).

Known bugs and warnings (October 2026)#

  • Issues #3236 (closed) and #10660 (open): crashes with permission denied or cannot move temporary file on Windows with data on a Windows-mounted folder or a Windows container volume. Our Docker Desktop bind mount worked, but if you see these errors, use a Docker named volume.
  • Issue #10319 (open): disk use can grow after forced or background merges. Watch free space.

First commands for any problem: docker compose ps, docker compose logs --tail=100 victoriametrics, docker inspect victoriametrics.

Updates and backups#

Update. Read the release notes, change the tag in docker-compose.yml, then:

Run in terminalbash
cd ~/docker_volumes/victoriametrics
docker compose pull
docker compose up -d
docker compose logs --tail=50 victoriametrics

The docs say upgrades are normally safe, and skipping versions is fine unless the notes say otherwise.

Back up. vmbackup makes an instant snapshot, copies it, and deletes the snapshot. VictoriaMetrics keeps running. The backup into latest is incremental after the first run. A dated copy is a quick server-side copy of latest.

Linux#

Save this as backup.sh in the project folder:

File contentbash
#!/bin/sh
cd ~/docker_volumes/victoriametrics || exit 1
docker compose run --rm vmbackup -storageDataPath=/storage -snapshot.createURL=http://victoriametrics:8428/snapshot/create -dst=fs:///backups/latest
docker compose run --rm vmbackup -origin=fs:///backups/latest -dst=fs:///backups/$(date +%Y%m%d)

Make it executable and schedule it for 03:00 with chmod +x backup.sh and crontab -e, adding 0 3 * * * $HOME/docker_volumes/victoriametrics/backup.sh. The backup files belong to root because the container runs as root, so deleting old dated folders needs sudo.

Windows (PowerShell)#

Save this as backup.ps1. Every flag is quoted:

Codepowershell
Set-Location "$HOME\docker_volumes\victoriametrics"
docker compose run --rm vmbackup "-storageDataPath=/storage" "-snapshot.createURL=http://victoriametrics:8428/snapshot/create" "-dst=fs:///backups/latest"
$day = Get-Date -Format yyyyMMdd
docker compose run --rm vmbackup "-origin=fs:///backups/latest" "-dst=fs:///backups/$day"

Schedule it with Task Scheduler at 03:00, for example schtasks /Create /SC DAILY /ST 03:00 /TN "VictoriaMetrics backup" /TR "powershell -File $HOME\docker_volumes\victoriametrics\backup.ps1". We ran the two backup commands, not the scheduled task.

Mac (Terminal)#

Same backup.sh and crontab entry as Linux. On macOS, cron may need Full Disk Access; we did not test this.

Check it worked. Real output from our Windows test:

Run in terminaltext
backup ... to fsremote "/backups/latest" with origin fsnil is complete; backed up 288726 bytes in 1.895 seconds
remote backup copy from fsremote "/backups/latest" to fsremote "/backups/20261031" is complete

The folder backups/ then holds latest and one folder per day. Delete old dated folders yourself.

Restore test. Restore into a new, empty named volume, never over the live data, and start a throwaway VictoriaMetrics on it:

Run in terminalbash
docker volume create vm-restore-test
docker run --rm -v "$HOME/docker_volumes/victoriametrics/backups:/backups" -v vm-restore-test:/restore victoriametrics/vmrestore:v1.155.0 "-src=fs:///backups/latest" "-storageDataPath=/restore"
docker run -d --name vm-restore-check -p 127.0.0.1:18428:8428 -v vm-restore-test:/storage victoriametrics/victoria-metrics:v1.155.0 "-storageDataPath=/storage"
curl -s "http://127.0.0.1:18428/api/v1/query?query=vm_app_version"
docker rm -f vm-restore-check && docker volume rm vm-restore-test

On Windows, replace the first mount path with ${PWD}\backups after changing into the project folder, and use curl.exe. In our test the restored copy answered with v1.155.0. A real recovery follows the docs: stop VictoriaMetrics, restore into the folder behind -storageDataPath, start again. On Windows that needs a named volume, because of the fallocate error above.

Performance and resources#

Measured on Windows 11 with Docker Desktop, about 12 minutes after the start, with only self-scraping: VictoriaMetrics 156 MiB of RAM and 0.4% CPU, Grafana 260 MiB and 2% CPU. The data folder was 369 KB. Real use grows with the number of series, so the numbers on your server will differ.

  • Look: docker stats --no-stream victoriametrics grafana.
  • Capacity: the docs ask you to leave 50% of RAM and CPU free and 20% of disk.
  • Memory knobs: -memory.allowedPercent (default 60) and -memory.allowedBytes limit how much RAM caches may use. Change them only if you must.
  • Claims: the project's own benchmarks claim up to 7x less RAM than Prometheus. Those are its numbers, not ours.

FAQ#

Is VictoriaMetrics free to use? Yes. The single-node and cluster versions are under Apache-2.0. A separate enterprise version adds features such as downsampling and anomaly detection.

Can it replace Prometheus? For storing and querying, yes: it accepts Prometheus remote write, reads prometheus.yml scrape files and answers the Prometheus query API. A few config sections are unsupported, so test your file.

Do I need Grafana? No. vmui, the built-in page at /vmui, runs queries and draws graphs. Grafana adds dashboards. You can use the Prometheus data source, as here, or the VictoriaMetrics data source plugin.

Can I run it on a Raspberry Pi? The Docker Hub tag has arm and arm64 images. We did not test a Pi.

Sources#

Checked against the official docs on 2026-10-31.