−25%

su Windows con pagamento annuale, fino al 31/10. Vai ai piani

EQVPS
Inizia

VPS per Langfuse: cosa hanno fatto i tuoi agenti IA

Langfuse in self-hosting: traccia ogni chiamata LLM e ogni passo degli strumenti dei tuoi agenti. Docker Compose testato, RAM reale e il piano giusto.

Un agente che lavora alle tre di notte senza nessuno a guardarlo vale quanto la tua capacità di ricostruire dopo cosa ha fatto. «Stanotte ha bruciato 38 $ di token» è una brutta mattinata. «Ha bruciato 38 $ perché uno strumento di ricerca ha restituito una pagina vuota e il planner ha riprovato 400 volte» è un bug che sistemi prima di pranzo. Per la seconda frase servono le tracce.

Langfuse registra ogni chiamata LLM, ogni prompt, passo di strumento, conteggio di token e latenza come un albero in cui puoi cliccare. Se lo ospiti tu, quei prompt e quelle risposte — che spesso contengono dati dei clienti, output di API e qualche segreto finito lì per sbaglio — restano su un server che controlli, non nel pannello di qualcun altro.

Quanto costa tenerlo acceso

Langfuse v4 non è un piccolo binario, ma sei container: l'app web, un worker in background, Postgres, ClickHouse per gli eventi, Redis e MinIO per i file. L'abbiamo installato su un server di prova e abbiamo misurato circa 3,5 GB di RAM in uso con un progetto vuoto. A crescere è ClickHouse, perché lì finisce ogni span che invii.

CaricoPiano
Una manciata di agenti, settimane di tracceMedium-IP: 6 vCPU, 6 GB, 45 GB ($20/mese)
Una flotta di agenti, mesi di storicoPiani Pro, da 32 GB di RAM in su — su richiesta

Sui piani più piccoli si installa, poi va in affanno appena ClickHouse e il worker vogliono memoria nello stesso momento. Io non scenderei sotto i 6 GB.

Dove vivono gli agenti? Se girano su altre macchine, scegli un piano con un IPv4 tutto suo: serve loro un endpoint HTTPS, e su un piano NAT l'indirizzo in uscita non è il tuo e dall'esterno si raggiunge solo la porta SSH. Se gli agenti girano su questo stesso server, Langfuse non deve mai affacciarsi su internet: per una prova basta Medium con NAT ($12/mese). Le località sono due, Germania e Finlandia; la disponibilità si vede al momento dell'ordine. Scegli quella più vicina agli agenti, non a te. I server si pagano in cripto, senza KYC.

Installazione

Su un server Ubuntu 24.04 o Debian 12 appena creato, come root. Prima Docker:

curl -fsSL https://get.docker.com | sh

Poi Langfuse, con segreti veri al posto dei valori di default del file compose:

git clone --depth 1 https://github.com/langfuse/langfuse.git
cd langfuse

PG=$(openssl rand -hex 16); MINIO=$(openssl rand -hex 16)
cat > .env <<EOF
NEXTAUTH_URL=https://langfuse.example.com
NEXTAUTH_SECRET=$(openssl rand -hex 32)
SALT=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$PG
DATABASE_URL=postgresql://postgres:$PG@postgres:5432/postgres
CLICKHOUSE_PASSWORD=$(openssl rand -hex 16)
MINIO_ROOT_PASSWORD=$MINIO
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=$MINIO
REDIS_AUTH=$(openssl rand -hex 16)
TELEMETRY_ENABLED=false
EOF
chmod 600 .env

Due di quelle password vanno in coppia: quella di Postgres sta anche dentro DATABASE_URL, e quella di MinIO deve coincidere con le tre righe S3_..._SECRET_ACCESS_KEY. Per questo ciascuna viene da una sola variabile.

Ora la trappola. Il file compose pubblica l'app web sulla porta 3000 e MinIO sulla 9090 su tutte le interfacce, e le porte pubblicate da Docker scavalcano ufw. Lega entrambe a localhost, così l'unico ingresso resta il reverse proxy:

sed -i 's/- 3000:3000/- 127.0.0.1:3000:3000/; s/- 9090:9000/- 127.0.0.1:9090:9000/' docker-compose.yml
docker compose up -d
curl -s http://127.0.0.1:3000/api/public/health

L'ultimo comando dovrebbe stampare {"status":"OK", ...}. Il primo avvio esegue le migrazioni del database; nella nostra prova l'health check è passato circa 15 secondi dopo l'avvio dei container.

HTTPS davanti

Punta langfuse.example.com sull'IP del server, poi:

apt install -y caddy
cat > /etc/caddy/Caddyfile <<'EOF'
langfuse.example.com {
    reverse_proxy 127.0.0.1:3000
}
EOF
systemctl reload caddy
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable

Caddy ottiene il certificato da solo. Apri il sito, crea il tuo account (diventa la prima organizzazione), aggiungi un progetto e copia le sue chiavi pubblica e segreta.

Poi chiudi la porta dietro di te. Langfuse capisce AUTH_DISABLE_SIGNUP, ma il file compose di serie non la passa al container web, quindi serve una riga in più sotto langfuse-web:

sed -i 's|^      NEXTAUTH_SECRET: \(.*\)$|      NEXTAUTH_SECRET: \1\n      AUTH_DISABLE_SIGNUP: ${AUTH_DISABLE_SIGNUP:-false}|' docker-compose.yml
echo "AUTH_DISABLE_SIGNUP=true" >> .env
docker compose up -d

Da qui in poi un tentativo di registrazione riceve «Sign up is disabled». I colleghi li aggiungi dall'interno del progetto.

Inviare tracce da un agente

L'SDK Python avvolge le tue funzioni, e le chiamate annidate diventano span annidati:

python3 -m venv venv && . venv/bin/activate
pip install langfuse
export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_BASE_URL=https://langfuse.example.com
from langfuse import get_client, observe

langfuse = get_client()  # legge le variabili LANGFUSE_*

@observe(name="fetch-prices")
def fetch_prices(pair: str) -> dict:
    return {"pair": pair, "bid": 64210.5}

@observe(name="nightly-agent-run")
def run() -> str:
    data = fetch_prices("BTC/USDT")
    return f"done: {data['pair']}"

print(run())
langfuse.flush()  # gli script brevi terminano prima che finisca l'invio in background

Non saltare LANGFUSE_BASE_URL. Senza, l'SDK manda tutto in silenzio al cloud di Langfuse, le tue chiavi lì non esistono e ti ritrovi a fissare un pannello vuoto.

Per verificare dalla console che gli span sono arrivati:

curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
  "$LANGFUSE_BASE_URL/api/public/v2/observations?limit=5"

In v4 il vecchio endpoint /api/public/traces risponde con un errore sulla modalità events-only. È previsto, non è un'installazione rotta. In un agente vero avvolgi allo stesso modo la chiamata LLM e ogni strumento; in più Langfuse ha integrazioni per gli SDK LLM e i framework per agenti più diffusi, quindi spesso basta cambiare un import invece di riempire tutto di decoratori.

Cosa tenere d'occhio

  • Disco. ClickHouse e MinIO conservano tutto ciò che invii. docker system df -v mostra dove è finito lo spazio. Se tracci prompt e risposte lunghi, i 45 GB di Medium-IP si riempiono in settimane, non in anni. Controlla una volta al mese; quando ti va stretto, un piano Pro da 400 GB o più è su richiesta.
  • Aggiornamenti. Il file compose fissa la versione major (:4). docker compose pull && docker compose up -d porta le correzioni al suo interno. Leggi il changelog prima di cambiare versione major: proprio con la v4 è sparito l'endpoint delle tracce.
  • Backup. Ciò che conta vive nei volumi Docker: Postgres tiene utenti, progetti e chiavi; ClickHouse e MinIO, le tracce. Copiali fuori dal server con una pianificazione.

Vale $20 al mese? Se i tuoi agenti spendono più di così in token — e la maggior parte degli agenti senza supervisione lo fa — sapere dove sono finiti i token si ripaga la prima volta che un ciclo va fuori controllo. Un piccolo agente che gira una volta al giorno non ha bisogno di niente di tutto questo: bastano un file di log e un contatore di token.

Correlati

Pronto a fare il deploy? Paga in crypto, niente KYC — online in circa un minuto.

Fai il deploy ora →

FAQ

Quanta RAM serve a Langfuse in self-hosting?

Sul nostro server di prova Langfuse v4 girava come sei container — web, worker, Postgres, ClickHouse, Redis e MinIO — e usava circa 3,5 GB di RAM con un progetto vuoto. ClickHouse cresce con ogni span che invii. Medium-IP (6 GB di RAM, 45 GB di disco) lo regge senza fatica per una manciata di agenti; un'intera flotta con mesi di storico richiede un piano Pro, disponibile su richiesta.

Mi serve un IP dedicato per Langfuse?

Solo se gli agenti girano altrove e mandano le tracce via internet: serve loro un endpoint HTTPS, e un piano NAT accetta dall'esterno solo la tua porta SSH. Se gli agenti stanno sullo stesso server, Langfuse può restare su localhost e il pannello lo apri con un tunnel SSH: per questo basta il piano Medium con NAT.

Il codice gira, ma il pannello resta vuoto. Perché?

Quasi sempre manca LANGFUSE_BASE_URL. Senza, l'SDK manda tutto al cloud di Langfuse, le tue chiavi self-hosted lì non esistono e al tuo server non arriva nulla. Metti nella variabile il tuo indirizzo.

L'endpoint /api/public/traces restituisce un errore. L'installazione è rotta?

No. Langfuse v4 funziona in modalità events-only, in cui quell'endpoint è disattivato. Leggi i dati da /api/public/v2/observations: è la chiamata con cui abbiamo verificato che i nostri span di prova erano arrivati.

Come impedisco agli sconosciuti di registrarsi sulla mia istanza?

Langfuse legge AUTH_DISABLE_SIGNUP, ma il docker-compose.yml di serie non passa la variabile al container web, quindi metterla solo in .env non serve. Aggiungi una riga all'ambiente di langfuse-web (il comando è più sotto), impostala a true dopo aver creato il tuo account e le registrazioni successive riceveranno «Sign up is disabled».

Commenti

Ancora nessun commento. Sii il primo.

Lascia un commento

I commenti sono moderati prima di comparire.