AxioDBCloud
Remote Database Access Made Simple
Deploy AxioDB in Docker or Cloud. Connect from anywhere with the same API you already know. Zero code changes, production-ready TCP protocol, automatic reconnection.
Why AxioDBCloud?
Zero Code Changes
Use the exact same API as embedded AxioDB. Just change from new AxioDB() to new AxioDBCloud()
Deploy Anywhere
Docker, AWS, Azure, Google Cloud, DigitalOcean, or your own servers. One instance, unlimited clients.
Auto-Reconnect
Built-in exponential backoff reconnection. Up to 10 retry attempts. Your app stays resilient.
Production Ready
1000+ concurrent connections, heartbeat monitoring, request correlation, connection pooling.
Server Setup
Option 1: Docker (Recommended)
The easiest way to deploy AxioDB with TCP access. Full instructions — simpledocker runquick start, then advanced env vars, volumes, and Compose — live on the dedicated Docker page:
Option 2: Node.js Application
Using this config, you can expose an AxioDB instance running inside one service (Service A) so it can be reached over TCP from another service (Service B) using the AxioDBCloud client — no shared filesystem, no HTTP layer, just a direct TCP connection between processes:
1const { AxioDB } = require('axiodb');2
3// Service A: the process that owns the data, exposed for other services to reach4const db = new AxioDB({5 GUI: false, // GUI (optional)6 RootName: 'MyDatabase', // Root database name7 CustomPath: './data', // Data directory8 TCP: true // Enable TCP server9});10
11// Server automatically starts on port 2701912console.log('AxioDB TCP Server running on port 27019');Default Port: TCP server listens on port 27019 (HTTP GUI uses 27018). Service B then connects with new AxioDBCloud("axiodb://service-a-host:27019") — see Client Usage below.
Client Usage
Basic Connection
1const { AxioDBCloud } = require('axiodb');2
3// Connect to remote AxioDB server4const client = new AxioDBCloud("axiodb://localhost:27019");5
6// Establish connection7await client.connect();8
9// Use exactly like embedded AxioDB!10const db = await client.createDB("ProductionDB");11const users = await db.createCollection("Users");12
13// All operations work identically15
16const results = await users.query({ name: "Alice" })17 .Limit(10)18 .Skip(0)19 .Sort({ createdAt: -1 })20 .exec();21
22console.log(results);23
24// Disconnect when done25await client.disconnect();Connection String Format
axiodb://[host]:[port]- • Local:
axiodb://localhost:27019 - • Remote:
axiodb://192.168.1.100:27019 - • Cloud:
axiodb://mydb.example.com:27019
Advanced Options
1const client = new AxioDBCloud("axiodb://localhost:27019", {2 timeout: 30000, // Request timeout (ms)3 reconnectAttempts: 10, // Max reconnect attempts4 reconnectDelay: 1000, // Initial delay (ms)5 heartbeatInterval: 30000, // Heartbeat every 30s6 maxPoolSize: 10, // Concurrent connections in the pool (default: 10)7 username: 'admin', // Only needed if the server has TCPAuth: true8 password: 'admin',9});maxPoolSize mirrors MongoDB's driver option of the same name. AxioDBCloud opens this many concurrent TCP connections to the server and routes each command to whichever connected member currently has the fewest in-flight requests (least-busy), so a burst of concurrent requests isn't serialized over a single socket, and a slow command on one connection doesn't queue new work behind it while other members sit idle. Each pooled connection reconnects and re-authenticates independently, so one dropped connection never blocks commands routed to the others.
Each pool member is a socket, and the server holds one socket per connected client - both count against the OS's open-file-descriptor limit (ulimit -n, often 1024 by default on Linux). At the default pool size that's enough for roughly 100 clients before the server starts refusing new connections. If you're deploying towards the 1,000+ concurrent connections the server supports, raise the limit (e.g. ulimit -n 65536, or docker run --ulimit nofile=65536:65536) rather than raising maxPoolSize per client.
The server also caps concurrent connections at 100 per remote IP, independent of the global 1,000-connection budget - so a single misbehaving or malicious client can't claim the entire pool of server connections for itself. This is checked at connect time, before authentication, and rejects the extra connection with a 429 ("Too many concurrent connections from this IP address"). A single client at the default maxPoolSize: 10 is nowhere near this limit.
If maxPoolSize asks for more connections than the server allows (from the per-IP cap above, or any other reason a handful of pool members fail),connect() doesn't reject outright - it resolves as long as at least one pool member connected, and emits a poolDegraded event so the app knows it's running with fewer connections than requested instead of failing (or silently under capacity):
1client.on('poolDegraded', ({ requested, connected, failed, errors }) => {2 console.warn(`Pool came up smaller than requested: ${connected}/${requested} connected, ${failed} failed`);3 console.warn(errors[0].message); // e.g. "Too many concurrent connections from this IP address"4});5
6await client.connect(); // resolves even if some pool members were rejectedThe one exception is the very first connection in the pool - if that one fails,connect() still rejects entirely, since it's the signal that the server is reachable and credentials are valid at all.
The 100-per-IP cap only bounds concurrent connections - by itself it wouldn't stop an attacker who never holds more than a few sockets open but rapidly opens and drops them, since each attempt still costs a TCP handshake and an accept/reject cycle. A separate per-IP rate limiter tracks connection attempts (successful or rejected, either counts) in a trailing 10-second window; once an IP crosses 300 attempts, every new connection from it is rejected with a 429 for the next 30 seconds. A normal client - even one repeatedly reconnecting a full maxPoolSize: 10 pool - is nowhere near this threshold.
TCP Authentication (NEW!)
TCP connections are unauthenticated by default (unchanged from before). Opt in with TCPAuth: true to require a username/password on every connection - it reuses the exact same accounts and roles as the GUI Control Server's RBAC system, so there's only one set of credentials to manage.
Server
1const db = new AxioDB({2 TCP: true,3 TCPAuth: true, // Require authentication on every TCP connection4 RootName: 'MyDatabase',5 CustomPath: './data',6});Client
1// Pass credentials in the constructor options - connect() authenticates automatically2const client = new AxioDBCloud("axiodb://localhost:27019", {3 username: 'admin',4 password: 'admin',5});6await client.connect();7
8console.log(client.authenticatedUser);9// { username: 'admin', role: 'Super Admin', mustChangePassword: false }10
11// Or authenticate after connecting (e.g. credentials supplied at runtime)12const client2 = new AxioDBCloud("axiodb://localhost:27019");13await client2.connect();14await client2.login('admin', 'admin');What's enforced
- • Every command except PING/DISCONNECT/AUTHENTICATE requires a prior successful login on that connection
- • Same role permissions as the GUI, checked per command (e.g. a View-role user gets 403 on CREATE_DB)
- • Shared per-IP login rate limiter with the GUI: 5 failed attempts in 15 minutes locks that IP out for 15 minutes (429)
- • Accounts still needing their forced password change are rejected outright (403) - complete it via the GUI first
- • A password reset, role change, or deletion via the GUI immediately forces an already-open TCP connection to re-authenticate
Known limitations
- • No TCP command exists yet to change a password - that must go through the GUI
TLS Encryption (NEW!)
By default, the TCP protocol is plaintext - anyone who can capture network traffic between client and server (e.g. Wireshark on a shared network) can read your data and, if TCPAuth is on, your password. TLS fixes this. It's off by default - nothing here is required, and existing plaintext deployments keep working exactly as before unless you turn it on.
You must provide your own certificate + key. AxioDB never generates one for you - that's a security decision only you can make (a real cert from a CA, or a self-signed one for local/private use).
Step 1 - Get a cert + key
For local/dev/private use, generate a self-signed one (one-time, takes a second):
1openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"This creates two files, cert.pem and key.pem, in your current folder. For a real production deployment reachable from the internet, use a cert from a real CA (Let's Encrypt, your org's CA, your cloud provider's managed cert) instead - the rest of the setup is identical either way.
Step 2 - Point the server at them
1const { AxioDB } = require('axiodb');2const db = new AxioDB({3 TCP: true,4 TLS: true,5 TLSCertPath: './cert.pem', // path to the file from step 16 TLSKeyPath: './key.pem',7});If TLS: true but either path is missing or unreadable, AxioDB throws immediately at startup - it never silently falls back to plaintext.
Step 3 - Point the client at the same cert
Only needed because it's self-signed - a real CA-issued cert wouldn't need this step, the same way your browser trusts https:// sites without extra setup:
1const { AxioDBCloud } = require('axiodb');2const client = new AxioDBCloud("axiodb://localhost:27019", {3 tls: true,4 tlsCAPath: './cert.pem', // same cert.pem from step 1 - proves this server is the real one5});6await client.connect();Without tlsCAPath, the client refuses to connect to a self-signed server by default (tlsRejectUnauthorized defaults to true) - this is intentional, the same protection that stops a browser from silently trusting a fake https:// site. Only set tlsRejectUnauthorized: false for local/dev testing, never in production, since it turns that protection off entirely.
Running this in Docker?
The cert/key files need to get into the container. The simplest way to think about it: your cert files live on your real machine; a Docker bind mount (-v) makes a folder from your machine visible inside the container at whatever path you choose, and you point the env vars at that in-container path, not your real machine's path:
1# cert.pem and key.pem are really at /home/you/mycerts/ on your machine.2# "/certs" below is just a name we're choosing for where they'll appear inside the container.3docker run -d --name axiodb-server \4 -p 27018:27018 -p 27019:27019 \5 -v /home/you/mycerts:/certs:ro \6 -e AXIODB_TLS=true \7 -e AXIODB_TLS_CERT_PATH=/certs/cert.pem \8 -e AXIODB_TLS_KEY_PATH=/certs/key.pem \9 theankansaha/axiodbThe rule: the AXIODB_TLS_CERT_PATH value must always match the right-hand side of the -v mount (/certs/...), never the real path on your machine - the container can't see your machine's filesystem directly, only whatever you've explicitly mounted into it.
Complete API Examples
CRUD Operations
1// Insert single document2await users.insert({ name: "Bob", age: 30 });3
4// Insert multiple documents5await users.insertMany([6 { name: "Charlie", age: 25 },7 { name: "Diana", age: 28 }8]);9
10// Query documents11const adults = await users.query({ age: { $gte: 18 } })12 .Limit(10)13 .Sort({ age: -1 })14 .exec();15
16// Update document17await users.update({ name: "Bob" }).UpdateOne({ age: 31 });18
19// Delete document20await users.delete({ name: "Charlie" }).deleteOne();21
22// Aggregation23const stats = await users.aggregate([24 { $match: { age: { $gte: 25 } } },25 { $group: { _id: null, avgAge: { $avg: "$age" } } }26]).exec();Real-World Example: E-commerce App
1const { AxioDBCloud } = require('axiodb');2
3async function main() {4 // Connect to production database5 const client = new AxioDBCloud("axiodb://prod.example.com:27019");6 await client.connect();7
8 const db = await client.createDB("EcommerceDB");9 const products = await db.createCollection("Products");10 const orders = await db.createCollection("Orders");11
12 // Add new product13 await products.insert({14 sku: "LAPTOP-001",15 name: "Gaming Laptop",16 price: 1299.99,17 stock: 15,18 category: "Electronics"19 });20
21 // Get low stock products22 const lowStock = await products.query({ stock: { $lt: 10 } })23 .Sort({ stock: 1 })24 .exec();25
26 console.log("Low stock products:", lowStock.data.documents);27
28 // Create order29 await orders.insert({30 orderId: "ORD-12345",31 customerId: "USER-001",32 items: [{ sku: "LAPTOP-001", quantity: 1 }],33 total: 1299.99,34 status: "pending"35 });36
37 // Get today's orders38 const today = new Date().toISOString().split('T')[0];39 const todayOrders = await orders.query({40 createdAt: { $regex: today }41 }).exec();42
43 console.log("Today's orders:", todayOrders.data.documents.length);44
45 await client.disconnect();46}47
48main().catch(console.error);Features & Capabilities
35+ Commands
Full CRUD, aggregation, indexing support
Optional Auth (NEW!)
Shared RBAC with the GUI, per-IP rate limiting
Auto-Reconnect
Exponential backoff with 10 retry attempts
Heartbeat
PING/PONG every 30 seconds
Connection Pool
1000+ concurrent connections
Fast Protocol
Binary JSON with 4-byte length prefix
TypeScript
Full type definitions included
Perfect For
Microservices
Share one AxioDB instance across multiple services
Desktop Apps
Electron apps connecting to local or remote database
Cloud Deployments
Deploy to AWS, Azure, Google Cloud, DigitalOcean
Ready to Get Started?
Deploy AxioDB in minutes and start connecting from anywhere.
