CGRateS on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of CGRateS on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images.
CGRateS is a carrier grade, real time charging system from ITsysCOM. It rates, charges and bills usage metered services — voice calls, VoIP, SMS, data, and any custom usage record — with pluggable rating plans, destinations, tariffs, balances, chargers, attributes and CDR handling. Everything is driven through a JSON-RPC API and the cgr-console CLI, so it slots in behind session managers and agents (FreeSWITCH, Kamailio, Asterisk, Diameter, Radius) or in front of your own provisioning.
This image delivers CGRateS 0.10.5 installed from the official CGRateS apt repository, fully configured and hardened, so the engine is answering and rating calls within minutes of first boot.
Self contained by design. The engine's DataDB (active accounts, rating data) is a local Redis bound to loopback with a per VM password, and the StorDB is CGRateS's own internal store — so there is no external SQL database to install, run or secure. The only datastore on the box is a loopback only Redis.
Security by design, no baked credential. The CGRateS engine's RPC and HTTP JSON-RPC listeners are bound to 127.0.0.1 only and are never exposed off box — they carry no authentication of their own, which is exactly why they must stay on loopback. The HTTP JSON-RPC endpoint is fronted by nginx on port 443 with a per VM self signed TLS certificate and per VM HTTP Basic Auth; port 80 redirects to 443. On first boot each VM generates a unique Redis password, a unique Basic Auth password and a unique TLS certificate, writes them to the root only file /root/cgrates-credentials.txt, and loads a sample tariff plan so the engine rates a call immediately.
What is included:
- CGRateS 0.10.5 installed from the official CGRateS apt repository, running under systemd as
cgrates.service - The full CGRateS tool set on the default
PATH:cgr-engine,cgr-loader,cgr-console,cgr-tester,cgr-migrator - A loopback only Redis DataDB (per VM password) and an internal StorDB — no external SQL database
- An nginx TLS reverse proxy on port 443 (per VM certificate + per VM HTTP Basic Auth) in front of the loopback JSON-RPC HTTP API
- A sample tariff plan (accounts 1001-1004 with balances, destinations, rating plans and chargers) loaded on first boot, so the engine rates a call and returns balances the moment the VM is up
- Per VM Redis password, Basic Auth password and TLS certificate generated on first boot, written to a root only credentials file
- No swap in the image; the stack fits a
Standard_B2sin RAM
Deploying the VM
Launch the image from the Azure Marketplace as you would any other VM. The recommended size is Standard_B2s (2 vCPU / 4 GiB). Higher call volumes benefit from more memory for Redis and the rater — move to a larger SKU if you load large tariff plans or keep many active sessions.
CGRateS is reached off box only through nginx on TCP 443 (with 80 redirecting to 443). The Azure network security group is your first line of defence: open 443 only to the client addresses or subnets that genuinely need the API, never to the whole internet. The per VM Basic Auth password and TLS are the second and third layers, but the NSG is the one that keeps unwanted traffic off the box entirely. The engine's own ports (2012, 2013, 2080) and Redis (6379) are bound to loopback and are never in the NSG.
First boot
On the first boot of each VM a one shot service, cgrates-firstboot.service, prepares the instance:
- mints a per VM Redis password and applies it to Redis (loopback only),
- writes that password into the engine config (
/etc/cgrates/cgrates.json), - generates a per VM self signed TLS certificate whose common name is the VM's public IP,
- mints a per VM HTTP Basic Auth password for the nginx front door (user
admin), - writes
/root/cgrates-credentials.txt(mode600, root only), - starts the engine and loads the sample tariff plan so the engine rates a call out of the box.
No two VMs ever share a credential, and the engine will not start until first boot has minted the real per VM Redis password — so the vendor default never runs.
Retrieving your per VM credentials
Connect over SSH as azureuser, then read the root only credentials file:
sudo cat /root/cgrates-credentials.txt
Expected output (secrets shown here as ****):
# CGRateS 0.10.5 — generated on first boot by cgrates-firstboot.service
# These credentials are unique to this VM. Store them somewhere safe.
cgrates.url=https://20.0.0.10/jsonrpc
# 1) HTTP Basic Auth guards the nginx TLS front door to the CGRateS JSON-RPC HTTP API:
cgrates.basicauth.user=admin
cgrates.basicauth.pass=****
# 2) Redis (CGRateS DataDB) per-VM password — loopback only, 127.0.0.1:6379, logical DB 10:
cgrates.redis.pass=****

Keep this file safe — it is the only copy of the per VM secrets, and it is readable only by root.
Checking service health
Three services back the appliance: redis-server (the DataDB), cgrates (the engine) and nginx (the TLS front door). Confirm all three are active and that the engine answers its JSON-RPC ping:
sudo systemctl is-active redis-server cgrates nginx
cgr-engine -version
curl -s http://127.0.0.1:2080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{"id":1,"method":"CoreSv1.Ping","params":[{}]}'
Expected output:
active
active
active
CGRateS@v0.10.5
{"id":1,"result":"Pong","error":null}
Pong from CoreSv1.Ping confirms the engine is up and dispatching RPC. The engine binds 127.0.0.1 only on ports 2012 (JSON-RPC), 2013 (GOB-RPC) and 2080 (HTTP JSON-RPC); nothing off box reaches it directly.

The sample tariff plan
A tariff plan is the set of destinations, rates, rating plans, rating profiles, account actions, chargers and attributes that tells CGRateS how to price usage. The image preloads the sample tutorial plan on first boot; you can reload it at any time with cgr-loader (it reads the per VM Redis password from the credentials file):
RP=$(sudo grep '^cgrates.redis.pass=' /root/cgrates-credentials.txt | cut -d= -f2-)
sudo cgr-loader -verbose \
-path=/usr/share/cgrates/tariffplans/tutorial \
-datadb_passwd="$RP" 2>&1 | tail -5
Expected output (the loader prints the tables it writes, then completes):
2026/08/11 11:34:59 Processing folder /usr/share/cgrates/tariffplans/tutorial
2026/08/11 11:34:59 Writing to DataDB
2026/08/11 11:34:59 Done.

Rating a call and querying a balance
This is the reason the engine exists. The sample plan provisions accounts 1001 to 1004. Query account 1001's balance, then rate a 20 second call from 1001 to 1002:
cgr-console 'accounts Tenant="cgrates.org" AccountIDs=["1001"]'
cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1002" AnswerTime="2014-08-04T13:00:00Z" Usage="20s"'
The account query returns a *monetary balance of 10; the cost query returns a Cost for the rated call:
[
{
"BalanceMap": {
"*monetary": [ { "ID": "test", "Value": 10, "Weight": 10 } ]
},
"ID": "cgrates.org:1001",
"Disabled": false
}
]
{
"Cost": 0.6,
"Charges": [ { "RatingID": "2e7fc13", "Increments": [ ... ] } ],
"Tenant": "cgrates.org",
"Subject": "1001",
"Destination": "1002",
"Usage": "20s"
}
A non-zero Cost means the engine walked the destination, rating plan and rate tables and priced the call end to end. This is your definitive "the engine is live and rating" check.

Calling the API through the nginx TLS front door
Off box, the JSON-RPC API is reached over HTTPS through nginx, guarded by HTTP Basic Auth. The certificate is a per VM self signed cert, so pass -k (or install your own certificate — see below). Replace <CGRATES_BASICAUTH_PASSWORD> with the cgrates.basicauth.pass value from your credentials file, and use the VM's public IP:
curl -sk -u "admin:<CGRATES_BASICAUTH_PASSWORD>" https://127.0.0.1/jsonrpc \
-H 'Content-Type: application/json' \
-d '{"id":1,"method":"APIerSv1.GetAccount","params":[{"Tenant":"cgrates.org","Account":"1001"}]}'
Expected output (the same account, now fetched through the authenticated TLS front door):
{"id":1,"result":{"ID":"*out:cgrates.org:1001","BalanceMap":{"*monetary*out":[{"ID":"test","Value":10,"Weight":10}]},"Disabled":false},"error":null}
Without the -u credential the front door returns 401; with a wrong password it also returns 401. Only the per VM Basic Auth password gets through to the engine.
Loading your own tariff plans
Author your own plan as a folder of CSV files (the same schema as the sample) and load it the same way (replace the path with your own):
$ RP=$(sudo grep '^cgrates.redis.pass=' /root/cgrates-credentials.txt | cut -d= -f2-)
$ sudo cgr-loader -verbose -path=/path/to/your/tariffplan -datadb_passwd="$RP"
The CSV schema is documented at cgrates.readthedocs.io. The sample plan under /usr/share/cgrates/tariffplans/tutorial is a working reference to copy and adapt.
Installing your own TLS certificate
The image ships a per VM self signed certificate so the API is encrypted from first boot. For production, replace it with a certificate for your own domain (for example from Let's Encrypt) and point nginx at it:
$ sudo cp /path/to/fullchain.pem /etc/nginx/ssl/cgrates.crt
$ sudo cp /path/to/privkey.pem /etc/nginx/ssl/cgrates.key
$ sudo chmod 600 /etc/nginx/ssl/cgrates.key
$ sudo nginx -t && sudo systemctl reload nginx
Changing the credentials
Change the nginx Basic Auth password (you will be prompted for the new password):
$ sudo htpasswd /etc/nginx/.cgrates.htpasswd admin
$ sudo systemctl reload nginx
Change the Redis password: set a new requirepass in /etc/redis/redis.conf and the matching data_db.db_password in /etc/cgrates/cgrates.json, then restart both services:
$ sudo systemctl restart redis-server cgrates
Where things live
| Path | Purpose |
|---|---|
/usr/bin/cgr-engine |
The CGRateS engine daemon (run by cgrates.service) |
/usr/bin/cgr-loader |
Loads tariff plan CSVs into the DataDB |
/usr/bin/cgr-console |
JSON-RPC CLI client for a running engine |
/etc/cgrates/cgrates.json |
Engine config (loopback listeners, Redis DataDB, internal StorDB) |
/etc/redis/redis.conf |
Redis (DataDB) config — loopback only, per VM password |
/etc/nginx/sites-available/cgrates |
nginx TLS reverse proxy vhost (:443) |
/etc/nginx/ssl/cgrates.crt / .key |
Per VM TLS certificate |
/etc/nginx/.cgrates.htpasswd |
Per VM HTTP Basic Auth users |
/root/cgrates-credentials.txt |
Per VM secrets (root only, mode 600) |
/usr/share/cgrates/tariffplans/tutorial |
The sample tariff plan |
Switching StorDB to MySQL or Postgres
The StorDB is *internal by default, which keeps CDRs and offline data in process — perfect for a self contained appliance. If you need durable CDR archival or the offline API, install MySQL or Postgres, load the CGRateS schema (shipped under /usr/share/cgrates/storage), and set stor_db.db_type in /etc/cgrates/cgrates.json accordingly, then restart cgrates. The DataDB stays on Redis. cloudimg support can walk you through this.
Security checklist
- Restrict the NSG. Expose only port 443 (and 22 for SSH) to the specific clients that need it. The engine and Redis are already loopback only.
- Install a real TLS certificate for your domain and remove the self signed one.
- Rotate the Basic Auth and Redis passwords if the credentials file is ever exposed.
- Keep the OS patched —
unattended-upgradesis enabled so security updates apply automatically.
Troubleshooting
- Engine not answering
Pong: checksudo systemctl status cgratesandsudo journalctl -u cgrates -n 50. A DataDB auth error means the Redis password incgrates.jsonandredis.confdisagree. 401from the front door: you are missing the Basic Auth credential, or using the wrong password — re-read/root/cgrates-credentials.txt.costreturns nothing / a zero cost: the tariff plan is not loaded — re-runcgr-loaderas shown above and confirm accounts1001-1004exist.- First boot did not run: check
sudo systemctl status cgrates-firstbootand confirm/var/lib/cloudimg/cgrates-firstboot.doneexists.
Further reading
- CGRateS documentation: cgrates.readthedocs.io
- CGRateS source (AGPL-3.0): github.com/cgrates/cgrates
Support
cloudimg provides 24/7 technical support for this CGRateS image by email at support@cloudimg.co.uk. We help with deployment, writing and loading tariff plans, using the JSON-RPC API and cgr-console, adding TLS and a custom domain, switching StorDB to MySQL or Postgres, integrating session and agent modules, performance tuning, upgrades and troubleshooting.