@fibercom/routeros-api
v2.0.0
Published
Robust MikroTik RouterOS API client for Node.js and TypeScript
Maintainers
Readme
@fibercom/routeros-api
A TypeScript and Node.js client for the MikroTik RouterOS API.
The library supports plain TCP and TLS connections, tagged concurrent commands, continuous data streams, connection retries, RouterOS traps, and convenience methods for common router operations.
Features
- TypeScript declarations and strict type checking
- RouterOS API over TCP or TLS
- Tagged commands on a shared connection
- Long-running streams with pause, resume, and close support
- Safe incremental decoding across fragmented TCP packets
- RouterOS
!re,!done,!trap,!fatal, and!emptyreplies - DHCP lease, firewall, route, interface, user, log, and system helpers
- Legacy RouterOS challenge-response login compatibility
- Configurable retries, timeouts, keepalive, and debug output
Requirements
- Node.js 14 or newer
- MikroTik RouterOS API service enabled
- Network and firewall access to the API port
RouterOS normally uses:
8728for the unencrypted API service8729for API-SSL
Installation
npm install @fibercom/routeros-apiBasic usage
const { MikrotikAPI } = require("@fibercom/routeros-api");
async function main() {
const api = new MikrotikAPI({
host: "192.168.88.1",
user: "api-user",
password: "your-password",
timeout: 10,
});
api.on("error", (error) => {
console.error("Router error:", error.message);
});
api.on("timeout", (error) => {
console.error("Router timeout:", error.message);
});
try {
await api.connect();
const identity = await api.getSystemIdentity();
const resources = await api.getSystemResources();
console.log({ identity, resources });
} finally {
if (api.connected) await api.close();
}
}
main().catch(console.error);TypeScript usage
import { MikrotikAPI, IRosOptions } from "@fibercom/routeros-api";
const options: IRosOptions = {
host: "192.168.88.1",
user: "api-user",
password: "your-password",
timeout: 10,
};
const api = new MikrotikAPI(options);
await api.connect();
const interfaces = await api.getInterfaces();
await api.close();TLS connection
Use RouterOS API-SSL whenever the connection crosses an untrusted network.
const api = new MikrotikAPI({
host: "router.example.com",
user: "api-user",
password: "your-password",
tls: true,
});When tls is enabled and port is omitted, the library uses port 8729.
You can pass Node.js TLS options instead of true:
const fs = require("fs");
const api = new MikrotikAPI({
host: "router.example.com",
user: "api-user",
password: "your-password",
tls: {
ca: fs.readFileSync("router-ca.pem"),
servername: "router.example.com",
rejectUnauthorized: true,
},
});Port 8728 is unencrypted. Usernames, passwords, commands, and responses can be
observed by anyone able to inspect that network traffic.
Connection retries
await api.connectWithRetry(3, 1000);Arguments:
- Maximum connection attempts
- Delay between attempts in milliseconds
A socket timeout produces:
Connection timeout. Possible firewall enabled, RouterOS API service disabled, or host unreachable.Raw RouterOS commands
Use write() for any RouterOS API command that does not have a convenience
method:
const addresses = await api.write([
"/ip/address/print",
"?interface=bridge",
]);The method accepts either one array or multiple command arguments:
const identity = await api.write("/system/identity/print");
await api.write(
"/system/identity/set",
"=name=core-router"
);RouterOS response values are returned as strings in plain JavaScript objects.
DHCP leases
Get every lease:
const leases = await api.getDhcpLeases();Filter by an exact DHCP server name:
const leases = await api.getDhcpLeases("Dhcp-mgmt");RouterOS query values are case-sensitive. Use the exact server name returned by:
const servers = await api.write("/ip/dhcp-server/print");Add a static lease:
await api.addDhcpLease({
address: "192.168.88.20",
macAddress: "00:11:22:33:44:55",
server: "Dhcp-mgmt",
comment: "Office printer",
disabled: false,
});Update a lease:
await api.setDhcpLease("*1A", {
address: "192.168.88.21",
comment: "Updated printer address",
});Block or unblock a lease using the Blocked firewall address list:
await api.blockDhcpLeaseById("*1A", "Blocked by billing");
await api.unblockDhcpLeaseById("*1A");Some DHCP helpers update multiple RouterOS resources sequentially. If a command fails midway, earlier router changes are not automatically rolled back.
Live interface traffic
const stream = api.streamInterfaceStats(
{
interface: "sfp-sfpplus1",
interval: 1,
},
(error, packet) => {
if (error) {
console.error(error.message);
return;
}
console.log(
packet["rx-bits-per-second"],
packet["tx-bits-per-second"]
);
}
);
await new Promise((resolve) => setTimeout(resolve, 5000));
await stream.pause();
await new Promise((resolve) => setTimeout(resolve, 3000));
await stream.resume();
await new Promise((resolve) => setTimeout(resolve, 5000));
await stream.close();A paused stream remains registered with the API. Resuming creates a fresh
RouterOS command tag. Calling close() or stop() performs final cleanup.
Streams also emit events:
stream.on("data", (packet) => console.log(packet));
stream.on("paused", () => console.log("paused"));
stream.on("started", () => console.log("started"));
stream.on("done", () => console.log("done"));
stream.on("close", () => console.log("closed"));
stream.on("stopped", () => console.log("stopped"));
stream.on("trap", (trap) => console.error("trap", trap));
stream.on("error", (error) => console.error(error));Convenience methods
System
getSystemInfo()getSystemResources()getSystemIdentity()setSystemIdentity(name)getSystemLogs(topics?)streamSystemLogs(callback?)reboot()exportConfig(filename?)importConfig(filename)
Interfaces and networking
getInterfaces()getIPAddresses()getInterfaceStats(interfaceName?)streamInterfaceStats(options, callback?)getBridges()getRoutes()addRoute(destination, gateway, distance?)
DHCP
getDhcpLeases(serverName?)addDhcpLease(lease)setDhcpLease(id, parameters)setDhcpLeaseAndUpdateAddressLists(id, parameters)removeDhcpLease(id)getDhcpServersWithGateways()getFreeIpsForDhcpServer(serverName, gatewayCidr)blockDhcpLeaseById(id, comment?)unblockDhcpLeaseById(id)
Firewall, wireless, and users
getFirewallRules(chain?)addFirewallRule(...)getWirelessInterfaces()getWirelessRegistrations()streamWirelessRegistrations(callback?)getUsers()addUser(name, password, group?)runScript(scriptName)
Connection options
interface IRosOptions {
host: string;
user?: string;
password?: string;
port?: number;
timeout?: number;
tls?: boolean | TlsOptions;
keepalive?: boolean;
debug?: boolean;
}timeout is measured in seconds.
Errors
RouterOS and connection failures use RosException:
const { RosException } = require("@fibercom/routeros-api");
try {
await api.connect();
} catch (error) {
if (error instanceof RosException) {
console.error(error.errno, error.message);
} else {
throw error;
}
}RouterOS !trap replies reject command promises. Listen for the API's error
and timeout events when maintaining a long-lived connection.
Live router smoke test
The repository includes a read-only test in index.js. It reads router system
information, interfaces, DHCP leases, and exercises traffic streaming with this
sequence:
start -> 5 seconds -> pause -> 3 seconds -> resume -> 5 seconds -> closeCopy .env.example to .env and configure it:
ROUTEROS_HOST=192.168.88.1
ROUTEROS_PORT=8728
ROUTEROS_USER=api-user
ROUTEROS_PASSWORD=change-me
ROUTEROS_TIMEOUT=10
ROUTEROS_TLS=false
ROUTEROS_DEBUG=false
ROUTEROS_TEST_INTERFACE=sfp-sfpplus1
ROUTEROS_DHCP_SERVER=Dhcp-mgmtThen run:
npm run test:routerThe .env file is ignored by Git. Do not commit router credentials.
Development
Install dependencies:
npm installBuild the library:
npm run buildRun strict compilation and the automated tests:
npm testWatch TypeScript sources:
npm run watchCompiled JavaScript and declarations are written to dist/.
Security
- Prefer API-SSL on port
8729. - Restrict API access with RouterOS firewall rules and
/ip serviceaddress restrictions. - Use a dedicated RouterOS user with only the permissions your application needs.
- Never commit passwords,
.envfiles, private keys, or router backups. - Test configuration-changing helpers on a non-production router first.
License
MIT
