Continuous Profiling
    Grafana Native

    Deploy Grafana Pyroscope on a VPS

    Run Grafana Pyroscope in monolithic mode on a RamNode VPS as a systemd service fronted by Caddy, with optional Grafana integration for continuous profiling.

    Target stack: Ubuntu 24.04 LTS, Pyroscope server as a single-binary (monolithic) systemd service, fronted by Caddy for TLS, with optional Grafana integration.

    Pyroscope is Grafana's continuous profiling backend. For a single VPS, run it in monolithic mode (all components in one process) — this is fine up to moderate scale and is what Grafana recommends for anything short of a dedicated cluster.


    1. Prerequisites

    shell
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl wget tar ufw
    shell
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable

    Pyroscope's own HTTP API/UI listens on port 4040 by default — we'll keep that bound to localhost and reverse-proxy it.

    2. Create a system user and directories

    shell
    sudo groupadd --system pyroscope
    sudo useradd --system --gid pyroscope --no-create-home \
      --shell /usr/sbin/nologin pyroscope
    
    sudo mkdir -p /etc/pyroscope /var/lib/pyroscope
    sudo chown -R pyroscope:pyroscope /var/lib/pyroscope

    3. Download and install the Pyroscope binary

    Check the Pyroscope releases page for the latest version and substitute it below.

    shell
    cd /tmp
    PYROSCOPE_VERSION="1.9.2"   # check for latest before running
    wget "https://github.com/grafana/pyroscope/releases/download/v${PYROSCOPE_VERSION}/pyroscope_${PYROSCOPE_VERSION}_linux_amd64.tar.gz"
    tar -xzf "pyroscope_${PYROSCOPE_VERSION}_linux_amd64.tar.gz"
    sudo mv pyroscope /usr/local/bin/pyroscope
    sudo chmod +x /usr/local/bin/pyroscope
    pyroscope --version

    4. Configure Pyroscope

    shell
    sudo tee /etc/pyroscope/config.yaml > /dev/null <<'EOF'
    target: all       # monolithic mode: runs all components in one process
    server:
      http_listen_address: "127.0.0.1:4040"
    
    storage:
      type: filesystem
      filesystem:
        dir: /var/lib/pyroscope
    
    # Retention: keep 14 days of profiles by default
    limits:
      compaction-block-selection-max-series-count: 100000
      max-profile-size-bytes: 20000000
    
    pyroscopedb:
      retention-policy:
        default-limit: 336h   # 14 days
    EOF
    
    sudo chown -R pyroscope:pyroscope /etc/pyroscope

    For real workloads, consider object storage (S3-compatible) instead of the local filesystem backend — add a storage.s3 (or compatible provider) block if you want profiles to survive disk loss.

    5. Create the systemd service

    shell
    sudo tee /etc/systemd/system/pyroscope.service > /dev/null <<'EOF'
    [Unit]
    Description=Grafana Pyroscope (continuous profiling)
    After=network.target
    
    [Service]
    Type=simple
    User=pyroscope
    Group=pyroscope
    ExecStart=/usr/local/bin/pyroscope --config.file=/etc/pyroscope/config.yaml
    Restart=on-failure
    RestartSec=5
    LimitNOFILE=65536
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
    sudo systemctl daemon-reload
    sudo systemctl enable --now pyroscope
    sudo systemctl status pyroscope

    6. Front it with Caddy (TLS + reverse proxy)

    If Caddy isn't already installed:

    shell
    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
    sudo apt update && sudo apt install -y caddy

    Edit /etc/caddy/Caddyfile:

    shell
    pyroscope.example.com {
        reverse_proxy 127.0.0.1:4040
    }
    shell
    sudo systemctl reload caddy

    Now https://pyroscope.example.com serves the Pyroscope UI over TLS with an automatically issued cert.

    Security note: Pyroscope has no built-in authentication in OSS mode. Put it behind Caddy's basicauth directive or an SSO proxy before exposing it publicly:

    shell
    pyroscope.example.com {
        basicauth {
            admin $2a$14$hashedpasswordhere
        }
        reverse_proxy 127.0.0.1:4040
    }

    Generate the hash with caddy hash-password.

    7. Send profiles to Pyroscope

    Option A — Pull-based agent (recommended for whole-system/eBPF profiling)

    Grafana Alloy can scrape profiles from your applications and this host and push them in. Install Alloy:

    shell
    curl -O https://raw.githubusercontent.com/grafana/alloy/main/scripts/install.sh
    sudo apt install -y ./alloy_*.deb   # or follow the official Alloy install docs for the repo method

    In your Alloy config, add a pyroscope.write block pointing at http://127.0.0.1:4040 and a pyroscope.scrape or pyroscope.ebpf component to collect from your services.

    Option B — Push-based SDK (per-language)

    Add the Pyroscope client library to your app and point it at the server, e.g. for a Go service:

    shell
    import "github.com/grafana/pyroscope-go"
    
    pyroscope.Start(pyroscope.Config{
        ApplicationName: "my.service",
        ServerAddress:   "https://pyroscope.example.com",
    })

    Similar SDKs exist for Python, Ruby, Java, .NET, Node.js, and Rust — see the Pyroscope docs for the exact package per language.

    8. Connect Grafana (optional, if you run Grafana separately)

    In Grafana: Connections → Data sources → Add data source → Pyroscope, and set the URL to https://pyroscope.example.com. You can then explore flame graphs directly in Grafana Explore, or add profiling panels to dashboards.

    9. Verify

    shell
    curl -s http://127.0.0.1:4040/ready
    # Should return: ready

    Open https://pyroscope.example.com in a browser — you should see the Pyroscope UI, and once an app is instrumented, its profiles under Applications.

    10. Backups and updates

    • Back up /var/lib/pyroscope (or your object storage bucket) and /etc/pyroscope/config.yaml.
    • To upgrade: download the new release binary, replace /usr/local/bin/pyroscope, then sudo systemctl restart pyroscope.