[{"data":1,"prerenderedAt":193},["ShallowReactive",2],{"seo-verification":3,"blog-self-host-questdb-vps-time-series-database-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-self-host-questdb-vps-time-series-database-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":20,"publishedAt":21,"updatedAt":22,"category":23,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":130,"ctaBody":131,"ctaButton":132,"ctaUrl":133,"relatedPosts":134},568,"self-host-questdb-vps-time-series-database",{"fr":12,"en":10,"ar":13,"es":14},"self-host-questdb-vps","استضافة-questdb-على-vps-قاعدة-سلاسل-زمنية","autoalojar-questdb-vps-base-series-temporales","QuestDB on a VPS: a SQL time-series database","Install QuestDB on a VPS: an open-source time-series database with fast ingestion and SQL queries, plus a web console and a REST API.",7,0,false,true,"2026-11-06T00:00:00+00:00","2026-11-08T01:13:02+00:00",{"id":17,"name":24,"slug":25,"color":26,"icon":27},"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":17,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fself-host-questdb-vps-poster.svg",{"categorySlug":34,"appSlug":35},"databases","questdb","Timestamped measurements come from everywhere: sensors, API response times, market prices, application events. Storing them in a regular relational database works at first, then the tables grow and hourly aggregates get slow. QuestDB is an open-source time-series database (Apache-2.0 licence) built for exactly this: it receives data continuously and makes it queryable right away in SQL. This guide installs it on a VPS with Docker Compose, protects it with a password, sends data from curl and Python, then covers querying, CSV import, retention and backup.",[38,42,52,83,86,102,106,109,112,115,118,121,124,127],{"type":39,"title":40,"body":41},"h2","Why a time-series database","A time series is a sequence of dated values: a probe's temperature every ten seconds, the number of orders per minute. It is written a lot, rarely modified, and almost always queried by time range.\n\nQuestDB is built around that use. Each table has a designated time column and is split into partitions (by day or by hour), which keeps queries over a period fast and makes deleting old data instantaneous. Its SQL is still SQL, enriched with a few time-specific keywords.",{"type":43,"title":44,"items":45},"ul","What QuestDB brings",[46,47,48,49,50,51],"**Time-series SQL** — `SAMPLE BY`, `LATEST ON` and `ASOF JOIN` on top of standard SQL.","**Continuous ingestion** — InfluxDB Line Protocol over HTTP, with official clients for Python, Go, Java, Node.js, Rust and .NET.","**Web console** — SQL editor, drag-and-drop CSV import, charts of the results.","**REST API** — queries, CSV import and export over HTTP.","**PostgreSQL protocol** — your usual PostgreSQL drivers and tools.","**Time partitions** — fast queries over a period, old data deleted in one command.",{"type":53,"title":54,"headers":55,"rows":58},"comparison","QuestDB versus a regular PostgreSQL table",[5,56,57],"QuestDB","PostgreSQL alone",[59,63,67,71,75,79],[60,61,62],"Built for","Continuous timestamped measurements","General relational data",[64,65,66],"Aggregate by interval","SAMPLE BY 1h","date_trunc and GROUP BY",[68,69,70],"Latest value per series","LATEST ON","Subquery or DISTINCT ON",[72,73,74],"Align two streams in time","ASOF JOIN","Lateral join to write",[76,77,78],"Delete old history","DROP PARTITION","DELETE then VACUUM",[80,81,82],"Ingestion","Line Protocol, CSV, SQL","SQL and COPY",{"type":39,"title":84,"body":85},"Prerequisites","An Ubuntu 24.04 VPS with at least 2 GB of RAM and 20 GB of disk, Docker and the Compose plugin installed, and a name (subdomain) pointing to the VPS for HTTPS. QuestDB runs on the JVM: plan 4 GB of RAM if you ingest a lot of data or run heavy queries.",{"type":87,"title":88,"steps":89},"steps","Install QuestDB with Docker Compose",[90,93,96,99],{"title":91,"body":92},"Prepare the directory and the password","Create the application directory and a `.env` file holding the `admin` user's password.\n```bash\nmkdir -p \u002Fopt\u002Fquestdb && cd \u002Fopt\u002Fquestdb\necho \"ADMIN_PASSWORD=$(openssl rand -hex 16)\" > .env\nchmod 600 .env\n```",{"title":94,"body":95},"Write the docker-compose.yml","Ports are only published on the loopback interface: only nginx reaches the console and the API. `QDB_HTTP_USER` and `QDB_HTTP_PASSWORD` protect the whole HTTP API, `QDB_PG_PASSWORD` replaces the PostgreSQL protocol's factory password. TCP ingestion, unauthenticated in the open-source edition, is turned off, and `QDB_TELEMETRY_ENABLED` disables anonymous telemetry.\n```yaml\nservices:\n  questdb:\n    image: questdb\u002Fquestdb:10.1.0\n    restart: unless-stopped\n    ports:\n      - \"127.0.0.1:9000:9000\"\n      - \"127.0.0.1:8812:8812\"\n    environment:\n      QDB_HTTP_USER: \"admin\"\n      QDB_HTTP_PASSWORD: \"${ADMIN_PASSWORD}\"\n      QDB_PG_USER: \"admin\"\n      QDB_PG_PASSWORD: \"${ADMIN_PASSWORD}\"\n      QDB_LINE_TCP_ENABLED: \"false\"\n      QDB_HTTP_SETTINGS_READONLY: \"true\"\n      QDB_TELEMETRY_ENABLED: \"false\"\n    volumes:\n      - questdb-data:\u002Fvar\u002Flib\u002Fquestdb\n\nvolumes:\n  questdb-data: {}\n```",{"title":97,"body":98},"Start and check","Startup takes a few seconds. Without credentials the API answers 401; with them it returns the installed version.\n```bash\ndocker compose up -d\ncurl -s -o \u002Fdev\u002Fnull -w '%{http_code}\\n' 'http:\u002F\u002F127.0.0.1:9000\u002Fexec?query=SELECT%201'\ncurl -u admin:VOTRE_MOT_DE_PASSE 'http:\u002F\u002F127.0.0.1:9000\u002Fexec?query=SELECT%20build()'\n```",{"title":100,"body":101},"Publish over HTTPS with nginx","In your domain's vhost (certificate obtained with certbot), proxy to the local port. Raise `client_max_body_size` for CSV imports.\n```nginx\nlocation \u002F {\n    proxy_pass http:\u002F\u002F127.0.0.1:9000;\n    proxy_set_header Host $host;\n    proxy_set_header X-Forwarded-Proto $scheme;\n    client_max_body_size 256m;\n}\n```",{"type":103,"title":104,"body":105},"tip","Without QDB_HTTP_USER, the API is open to everyone","With no declared user, QuestDB accepts every HTTP request: anyone who knows the address can read your data **and** create, modify or drop tables in SQL. Keep authentication on, change the PostgreSQL protocol's factory password, and never publish ports 9000, 8812 or 9009 directly on the public IP: always go through the HTTPS reverse proxy.",{"type":39,"title":107,"body":108},"Send data","The simplest way is the InfluxDB Line Protocol over HTTP: one line per measurement, with the table name, tags and values. The table and its columns are created on the first write.\n```bash\ncurl -u admin:VOTRE_MOT_DE_PASSE -X POST \\\n  --data-binary 'capteurs,sonde=s1 temperature=21.5' \\\n  https:\u002F\u002Fvotre-domaine\u002Fwrite\n```\n\nFrom your code, an official client batches the lines and handles retries. In Python, after `pip install questdb`:\n```python\nfrom questdb.ingress import Sender, TimestampNanos\n\nconf = \"https::addr=votre-domaine:443;username=admin;password=VOTRE_MOT_DE_PASSE;\"\nwith Sender.from_conf(conf) as sender:\n    sender.row(\n        \"capteurs\",\n        symbols={\"sonde\": \"s1\"},\n        columns={\"temperature\": 21.5},\n        at=TimestampNanos.now(),\n    )\n```",{"type":39,"title":110,"body":111},"Query your series in SQL","In the web console or through the REST API (`\u002Fexec?query=…`), standard SQL works, and the time extensions spare you complicated queries.\n```sql\n-- Moyenne horaire par sonde\nSELECT timestamp, sonde, avg(temperature)\nFROM capteurs\nSAMPLE BY 1h;\n\n-- Dernière valeur connue de chaque sonde\nSELECT * FROM capteurs LATEST ON timestamp PARTITION BY sonde;\n```\n\nA program running on the VPS itself can also connect over the PostgreSQL protocol on `127.0.0.1:8812`, database `qdb`, user `admin` and the same password.",{"type":39,"title":113,"body":114},"Model a time-series table properly","Automatic creation on the first write is enough to get started. For a table meant to last, declare it yourself: you choose the types, the time column and the partitioning.\n```sql\nCREATE TABLE capteurs (\n  timestamp TIMESTAMP,\n  sonde SYMBOL,\n  temperature DOUBLE\n) TIMESTAMP(timestamp) PARTITION BY DAY WAL\nDEDUP UPSERT KEYS(timestamp, sonde);\n```\n\nThree choices matter. **The designated time column** (`TIMESTAMP(...)`) is the one QuestDB sorts and partitions on: every time extension relies on it. **The `SYMBOL` type** suits repeated labels (probe name, device code, ticker): the value is stored once and referenced, which saves disk and speeds up filters. **Partitioning** (`PARTITION BY DAY` or `HOUR`) depends on volume: a partition should stay a reasonable size, and it is the unit you will delete later.\n\nThe `DEDUP UPSERT KEYS` clause makes ingestion idempotent: if a client resends the same measurement after a network cut, the row is replaced instead of duplicated.",{"type":39,"title":116,"body":117},"Import and export CSV files","The console accepts CSV files by drag and drop. From the command line, `\u002Fimp` imports a file into a table and `\u002Fexp` exports a query result.\n```bash\ncurl -u admin:VOTRE_MOT_DE_PASSE -F data=@mesures.csv 'https:\u002F\u002Fvotre-domaine\u002Fimp?name=mesures'\ncurl -u admin:VOTRE_MOT_DE_PASSE -G --data-urlencode 'query=SELECT * FROM mesures' https:\u002F\u002Fvotre-domaine\u002Fexp > export.csv\n```",{"type":39,"title":119,"body":120},"Retention, disk and backup","Nothing expires on its own. Drop old partitions in SQL and schedule the command if needed. For a consistent backup, freeze the database state while you copy the `questdb-data` volume.\n```sql\nALTER TABLE capteurs DROP PARTITION\nWHERE timestamp \u003C dateadd('d', -90, now());\n\nCHECKPOINT CREATE;\n-- copiez le volume questdb-data, puis :\nCHECKPOINT RELEASE;\n```",{"type":39,"title":122,"body":123},"Update QuestDB","Read the release notes before moving to a new major version, then replace the image tag and restart: the data in the volume is kept.\n```bash\ncd \u002Fopt\u002Fquestdb\n# changez le tag de l'image dans docker-compose.yml, puis :\ndocker compose pull && docker compose up -d\n```",{"type":39,"title":125,"body":126},"Common errors and troubleshooting","**401 on every request.** The user or password does not match `QDB_HTTP_USER` and `QDB_HTTP_PASSWORD`. Check the `.env` file, then restart the container after any change: the variables are only read at startup.\n\n**413 during a CSV import.** The file exceeds the nginx limit. Raise `client_max_body_size` in the vhost, reload nginx, or split the file.\n\n**The container keeps restarting.** Read `docker compose logs questdb`. The most common cause is memory: QuestDB runs on the JVM and a 1 GB VPS is not enough. Move to at least 2 GB.\n\n**The disk fills up.** Nothing expires by default: schedule the deletion of old partitions and watch the size of the `questdb-data` volume with `docker system df -v`.\n\n**An application on the VPS cannot connect over PostgreSQL.** Use `127.0.0.1:8812`, database `qdb`, user `admin` and the password from `.env`: the factory password `quest` is refused.",{"type":39,"title":128,"body":129},"One-click install from the ServOrbit Marketplace","On a ServOrbit VPS, QuestDB installs from the Marketplace: the script deploys the official container, generates the `admin` user's password, enables authentication on the HTTP API and the PostgreSQL protocol, turns off telemetry and configures nginx over HTTPS, on a subdomain of your domain or on the VPS's free subdomain. The password is shown in your client area.","Your time series on your own VPS","A ServOrbit Ubuntu 24.04 VPS with 2 GB of RAM is enough to start QuestDB. One-click install from the Marketplace, HTTPS on your domain or on the VPS's free subdomain, password generated for you.","Install QuestDB","\u002Fapplications\u002Fdatabases\u002Fquestdb",[135,158,175],{"id":136,"slug":137,"slugs":138,"title":142,"excerpt":143,"readTime":144,"views":18,"isPinned":19,"noindex":19,"publishedAt":145,"updatedAt":146,"category":147,"categories":153,"featuredImage":30,"bgImage":31,"posterImage":155,"relatedSolution":156},64,"hosting-clickhouse-on-a-vps",{"fr":139,"en":137,"ar":140,"es":141},"heberger-clickhouse-vps","استضافة-clickhouse-على-خادم-vps","alojar-clickhouse-en-un-vps","Hosting ClickHouse on a VPS","Host ClickHouse on your VPS: a columnar analytical database for your logs, metrics, and dashboards. Docker, memory tuning, and SSL guide.",9,"2026-04-17T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":148,"name":149,"slug":150,"color":151,"icon":152},6,"Databases","bases-de-donnees","bg-teal-500\u002F10 text-teal-400","database",[154],{"id":148,"name":149,"slug":150,"color":151,"icon":152},"\u002Fblog\u002Fcovers\u002Fheberger-clickhouse-vps-poster.svg",{"categorySlug":34,"appSlug":157},"clickhouse",{"id":159,"slug":160,"slugs":161,"title":165,"excerpt":166,"readTime":148,"views":18,"isPinned":19,"noindex":20,"publishedAt":167,"updatedAt":168,"category":169,"categories":170,"featuredImage":30,"bgImage":31,"posterImage":172,"relatedSolution":173},565,"self-host-greptimedb-vps-observability-sql",{"fr":162,"en":160,"ar":163,"es":164},"self-host-greptimedb-vps","استضافة-greptimedb-على-vps-قاعدة-بيانات-المراقبة","autoalojar-greptimedb-vps-observabilidad-sql","GreptimeDB on a VPS: Metrics, Logs and Traces in SQL","Install GreptimeDB on a VPS: an observability database that brings metrics, logs and traces together, queryable with SQL, PromQL and from Grafana.","2026-11-04T00:00:00+00:00","2026-11-04T16:30:20+00:00",{"id":17,"name":24,"slug":25,"color":26,"icon":27},[171],{"id":17,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fself-host-greptimedb-vps-poster.svg",{"categorySlug":34,"appSlug":174},"greptimedb",{"id":176,"slug":177,"slugs":178,"title":182,"excerpt":183,"readTime":144,"views":184,"isPinned":19,"noindex":19,"publishedAt":185,"updatedAt":186,"category":187,"categories":188,"featuredImage":30,"bgImage":31,"posterImage":190,"relatedSolution":191},56,"postgresql-on-a-vps-a-reliable-and-controlled-database",{"fr":179,"en":177,"ar":180,"es":181},"heberger-postgresql-vps","postgresql-على-خادم-vps-قاعدة-بيانات-موثوقة-ومتحكم-بها","alojar-postgresql-en-un-vps","PostgreSQL on a VPS: reliable, controlled database","Host PostgreSQL on a VPS: production config, pgBackRest backups, streaming HA, RDS\u002FSupabase\u002FNeon comparison and OOM troubleshooting.",1,"2026-04-25T00:00:00+00:00","2026-10-21T15:21:37+00:00",{"id":148,"name":149,"slug":150,"color":151,"icon":152},[189],{"id":148,"name":149,"slug":150,"color":151,"icon":152},"\u002Fblog\u002Fcovers\u002Fheberger-postgresql-vps-poster.svg",{"categorySlug":34,"appSlug":192},"postgresql-stack",1794101180985]