Guía de despliegue

QuestDB en un VPS: base de datos de series temporales en SQL

Desplegar en un VPS Cloud →

Tutorial

QuestDB en un VPS: base de datos de series temporales en SQL

Autoalojamiento7 min de lectura4 pasos

Las mediciones con marca de tiempo llegan de todas partes: sensores, tiempos de respuesta de una API, cotizaciones, eventos de una aplicación. Guardarlas en una base relacional clásica funciona al principio; luego las tablas crecen y los agregados por hora se vuelven lentos. QuestDB es una base de datos de series temporales de código abierto (licencia Apache-2.0) pensada para este caso: recibe los datos de forma continua y los deja consultables al instante en SQL. Esta guía la instala en un VPS con Docker Compose, la protege con contraseña, le envía datos desde curl y Python y repasa las consultas, la importación CSV, la retención y la copia de seguridad.

Contenido· Por qué una base de series temporales1/14
  1. 01Por qué una base de series temporales
  2. 02Lo que aporta QuestDB
  3. 03QuestDB frente a una tabla PostgreSQL clásica
  4. 04Requisitos previos
  5. 05Instalar QuestDB con Docker Compose
  6. 06Sin QDB_HTTP_USER, la API queda abierta a todos
  7. 07Enviar datos
  8. 08Consultar tus series en SQL
  9. 09Modelar bien una tabla de series temporales
  10. 10Importar y exportar archivos CSV
  11. 11Retención, disco y copia de seguridad
  12. 12Actualizar QuestDB
  13. 13Errores frecuentes y solución de problemas
  14. 14Instalación en un clic desde el Marketplace de ServOrbit

Por qué una base de series temporales

Una serie temporal es una sucesión de valores fechados: la temperatura de una sonda cada diez segundos, el número de pedidos por minuto. Se escribe mucho, se modifica poco y casi siempre se consulta por intervalo de tiempo.

QuestDB está construida en torno a ese uso. Cada tabla tiene una columna de tiempo designada y se divide en particiones (por día o por hora), lo que mantiene rápidas las consultas sobre un periodo y hace inmediata la eliminación de los datos antiguos. Su SQL sigue siendo SQL, con algunas palabras clave propias del tiempo.

Lo que aporta QuestDB

  • SQL de series temporales — SAMPLE BY, LATEST ON y ASOF JOIN además del SQL estándar.
  • Ingesta continua — InfluxDB Line Protocol sobre HTTP, con clientes oficiales para Python, Go, Java, Node.js, Rust y .NET.
  • Consola web — editor SQL, importación CSV arrastrando el archivo, gráficos de los resultados.
  • API REST — consultas, importación y exportación CSV por HTTP.
  • Protocolo PostgreSQL — tus controladores y herramientas PostgreSQL de siempre.
  • Particiones de tiempo — consultas rápidas sobre un periodo y borrado de datos antiguos en un comando.

QuestDB frente a una tabla PostgreSQL clásica

Desplace la tabla

QuestDBSolo PostgreSQL
Pensada paraMediciones continuas con marca de tiempoDatos relacionales generales
Agregar por intervaloSAMPLE BY 1hdate_trunc y GROUP BY
Último valor por serieLATEST ONSubconsulta o DISTINCT ON
Alinear dos flujos en el tiempoASOF JOINJoin lateral que escribir
Borrar el historial antiguoDROP PARTITIONDELETE y después VACUUM
IngestaLine Protocol, CSV, SQLSQL y COPY

Requisitos previos

Un VPS Ubuntu 24.04 con al menos 2 GB de RAM y 20 GB de disco, Docker y el plugin Compose instalados, y un nombre (subdominio) que apunte al VPS para el HTTPS. QuestDB funciona sobre la JVM: prevé 4 GB de RAM si ingieres muchos datos o lanzas consultas pesadas.

Instalar QuestDB con Docker Compose

  1. Preparar el directorio y la contraseña

    Crea el directorio de la aplicación y un archivo .env con la contraseña del usuario admin.

    mkdir -p /opt/questdb && cd /opt/questdb
    echo "ADMIN_PASSWORD=$(openssl rand -hex 16)" > .env
    chmod 600 .env
  2. Escribir el docker-compose.yml

    Los puertos solo se publican en la interfaz de loopback: solo nginx llega a la consola y a la API. QDB_HTTP_USER y QDB_HTTP_PASSWORD protegen toda la API HTTP, QDB_PG_PASSWORD sustituye la contraseña de fábrica del protocolo PostgreSQL. La ingesta por TCP, sin autenticación en la edición de código abierto, queda desactivada, y QDB_TELEMETRY_ENABLED desactiva la telemetría anónima.

    services:
      questdb:
        image: questdb/questdb:10.1.0
        restart: unless-stopped
        ports:
          - "127.0.0.1:9000:9000"
          - "127.0.0.1:8812:8812"
        environment:
          QDB_HTTP_USER: "admin"
          QDB_HTTP_PASSWORD: "${ADMIN_PASSWORD}"
          QDB_PG_USER: "admin"
          QDB_PG_PASSWORD: "${ADMIN_PASSWORD}"
          QDB_LINE_TCP_ENABLED: "false"
          QDB_HTTP_SETTINGS_READONLY: "true"
          QDB_TELEMETRY_ENABLED: "false"
        volumes:
          - questdb-data:/var/lib/questdb
    
    volumes:
      questdb-data: {}
  3. Arrancar y comprobar

    El arranque tarda unos segundos. Sin credenciales la API responde 401; con ellas devuelve la versión instalada.

    docker compose up -d
    curl -s -o /dev/null -w '%{http_code}\n' 'http://127.0.0.1:9000/exec?query=SELECT%201'
    curl -u admin:VOTRE_MOT_DE_PASSE 'http://127.0.0.1:9000/exec?query=SELECT%20build()'
  4. Publicar en HTTPS con nginx

    En el vhost de tu dominio (certificado obtenido con certbot), redirige al puerto local. Aumenta client_max_body_size para las importaciones CSV.

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 256m;
    }

Sin QDB_HTTP_USER, la API queda abierta a todos

Sin usuario declarado, QuestDB acepta cualquier petición HTTP: quien conozca la dirección puede leer tus datos y crear, modificar o borrar tablas en SQL. Mantén la autenticación activa, cambia la contraseña de fábrica del protocolo PostgreSQL y no publiques nunca los puertos 9000, 8812 o 9009 directamente en la IP pública: pasa siempre por el proxy inverso HTTPS.

Enviar datos

Lo más sencillo es el InfluxDB Line Protocol sobre HTTP: una línea por medición, con el nombre de la tabla, etiquetas y valores. La tabla y sus columnas se crean con la primera escritura.

curl -u admin:VOTRE_MOT_DE_PASSE -X POST \
  --data-binary 'capteurs,sonde=s1 temperature=21.5' \
  https://votre-domaine/write

Desde tu código, un cliente oficial agrupa las líneas y gestiona los reintentos. En Python, tras pip install questdb:

from questdb.ingress import Sender, TimestampNanos

conf = "https::addr=votre-domaine:443;username=admin;password=VOTRE_MOT_DE_PASSE;"
with Sender.from_conf(conf) as sender:
    sender.row(
        "capteurs",
        symbols={"sonde": "s1"},
        columns={"temperature": 21.5},
        at=TimestampNanos.now(),
    )

Consultar tus series en SQL

En la consola web o mediante la API REST (/exec?query=…), el SQL estándar funciona y las extensiones de tiempo evitan consultas complicadas.

-- Moyenne horaire par sonde
SELECT timestamp, sonde, avg(temperature)
FROM capteurs
SAMPLE BY 1h;

-- Dernière valeur connue de chaque sonde
SELECT * FROM capteurs LATEST ON timestamp PARTITION BY sonde;

Un programa que se ejecute en el propio VPS también puede conectarse por el protocolo PostgreSQL en 127.0.0.1:8812, base qdb, usuario admin y la misma contraseña.

Modelar bien una tabla de series temporales

La creación automática con la primera escritura basta para empezar. Para una tabla que va a durar, declárala tú mismo: eliges los tipos, la columna de tiempo y la partición.

CREATE TABLE capteurs (
  timestamp TIMESTAMP,
  sonde SYMBOL,
  temperature DOUBLE
) TIMESTAMP(timestamp) PARTITION BY DAY WAL
DEDUP UPSERT KEYS(timestamp, sonde);

Tres decisiones importan. La columna de tiempo designada (TIMESTAMP(...)) es la que QuestDB usa para ordenar y particionar: todas las extensiones de tiempo se apoyan en ella. El tipo SYMBOL conviene a las etiquetas repetidas (nombre de sonda, código de dispositivo, símbolo bursátil): el valor se guarda una vez y se referencia, lo que ahorra disco y acelera los filtros. La partición (PARTITION BY DAY u HOUR) se elige según el volumen: una partición debe tener un tamaño razonable, y es la unidad que borrarás más adelante.

La cláusula DEDUP UPSERT KEYS hace la ingesta idempotente: si un cliente reenvía la misma medición tras un corte de red, la fila se sustituye en lugar de duplicarse.

Importar y exportar archivos CSV

La consola acepta archivos CSV arrastrándolos. Desde la línea de comandos, /imp importa un archivo en una tabla y /exp exporta el resultado de una consulta.

curl -u admin:VOTRE_MOT_DE_PASSE -F [email protected] 'https://votre-domaine/imp?name=mesures'
curl -u admin:VOTRE_MOT_DE_PASSE -G --data-urlencode 'query=SELECT * FROM mesures' https://votre-domaine/exp > export.csv

Retención, disco y copia de seguridad

Nada caduca por sí solo. Elimina las particiones antiguas en SQL y programa el comando si hace falta. Para una copia coherente, congela el estado de la base mientras copias el volumen questdb-data.

ALTER TABLE capteurs DROP PARTITION
WHERE timestamp < dateadd('d', -90, now());

CHECKPOINT CREATE;
-- copiez le volume questdb-data, puis :
CHECKPOINT RELEASE;

Actualizar QuestDB

Lee las notas de la versión antes de pasar a una versión mayor, sustituye la etiqueta de la imagen y reinicia: los datos del volumen se conservan.

cd /opt/questdb
# changez le tag de l'image dans docker-compose.yml, puis :
docker compose pull && docker compose up -d

Errores frecuentes y solución de problemas

401 en cada petición. El usuario o la contraseña no coinciden con QDB_HTTP_USER y QDB_HTTP_PASSWORD. Revisa el archivo .env y reinicia el contenedor tras cualquier cambio: las variables solo se leen al arrancar.

413 al importar un CSV. El archivo supera el límite de nginx. Aumenta client_max_body_size en el vhost, recarga nginx o divide el archivo.

El contenedor se reinicia en bucle. Lee docker compose logs questdb. La causa más habitual es la memoria: QuestDB funciona sobre la JVM y un VPS de 1 GB no basta. Pasa a 2 GB como mínimo.

El disco se llena. Nada caduca por defecto: programa el borrado de las particiones antiguas y vigila el tamaño del volumen questdb-data con docker system df -v.

Una aplicación del VPS no consigue conectarse por PostgreSQL. Usa 127.0.0.1:8812, la base qdb, el usuario admin y la contraseña del .env: la contraseña de fábrica quest se rechaza.

Instalación en un clic desde el Marketplace de ServOrbit

En un VPS de ServOrbit, QuestDB se instala desde el Marketplace: el script despliega el contenedor oficial, genera la contraseña del usuario admin, activa la autenticación en la API HTTP y el protocolo PostgreSQL, desactiva la telemetría y configura nginx en HTTPS, en un subdominio de tu dominio o en el subdominio gratuito del VPS. La contraseña aparece en tu área de cliente.

Tus series temporales en tu propio VPS

Un VPS ServOrbit Ubuntu 24.04 con 2 GB de RAM basta para arrancar QuestDB. Instalación en un clic desde el Marketplace, HTTPS en tu dominio o en el subdominio gratuito del VPS y contraseña generada para ti.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva