IDURAR ERP CRM
Overview
This guide covers the deployment and configuration of IDURAR ERP CRM on Ubuntu 24.04 on Azure using SecureAnyCloud Azure Marketplace images. IDURAR is a self hosted, open source ERP and CRM for small businesses and consultancies: it manages customers, raises quotes, turns them into invoices, records payments against those invoices, and renders any of them as a PDF you can send to a client. It is built on the MERN stack, with a React and Ant Design admin console in front of an Express API and a MongoDB datastore.
The SecureAnyCloud image ships the free and open source, AGPL-3.0 licensed IDURAR release 4.1.0, with the API, the prebuilt admin console, MongoDB and nginx already wired together and captured into the VM, so your instance is usable within a minute of first boot.
Nothing here ships with a known credential. That matters more than usual with this product: the upstream setup routine hard codes an administrator account, and upstream commits an environment file containing a placeholder token signing secret. This image ships neither. The seeded account is destroyed during the build, and a single administrator with a random 24 character password, a fresh signing secret and fresh MongoDB passwords are generated on the first boot of each VM, before the application is allowed to start. IDURAR has no public sign up route, so that one administrator is the only way in. Backed by 24/7 SecureAnyCloud support.
IDURAR is a trademark of its respective owner. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by IDURAR. It ships the free and open source AGPL-3.0 licensed self hosted software, with a single documented change described under "Differences from a stock install" below.
What is included:
- IDURAR ERP CRM 4.1.0 (AGPL-3.0), pinned by git tag and verified by SHA-256 checksum at build time
- The React and Ant Design admin console, prebuilt to same origin relative API paths so it works at any address with no reconfiguration
- Node.js 22 LTS running the Express API as
idurar.service, bound to the loopback interface only
- MongoDB 8.0 Community with SCRAM-SHA-256 authentication, bound to the loopback interface only
- nginx on port
80serving the console and reverse proxying/api,/downloadand/public
- PhantomJS 2.1.1 as the PDF rendering engine for invoices, quotes and payment receipts
idurar-firstboot.service, which generates every secret and the single administrator account on first boot
- No administrator account, no signing secret and no database password baked into the image
- Ubuntu 24.04 LTS base with latest security patches applied at build time
- Azure Linux Agent for seamless cloud integration and SSH key injection
- 24/7 SecureAnyCloud support with guaranteed 24 hour response SLA
Prerequisites
- An active Azure subscription, an SSH public key, and a VNet and subnet in the target region
- A subscription to the IDURAR ERP CRM listing on Azure Marketplace
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a small team. For heavier use or a large invoice history, choose Standard_D2s_v5 or larger. For NSG inbound rules, allow 22/tcp from your management network and 80/tcp from the networks that use the console. The image uses port 443/tcp once you attach your own certificate, as shown in Step 10.
Deploy from the Azure Portal
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for IDURAR ERP CRM by SecureAnyCloud, and select Create. On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80). Then select Review + create, and then Create.
Deploy from the Azure CLI
To deploy with the Azure CLI instead of the portal, run the following commands:
RG="idurar-prod"; LOCATION="eastus"; VM_NAME="idurar-01" IMAGE_URN="sac1647283583153:idurar-erp-crm-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name idurar-vnet --address-prefix 10.100.0.0/16 --subnet-name idurar-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name idurar-nsg az network nsg rule create -g "$RG" --nsg-name idurar-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name idurar-nsg --name allow-http --priority 110 \
--destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:idurar-erp-crm-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name idurar-vnet --subnet idurar-subnet --nsg idurar-nsg --public-ip-sku StandardConfirm the services are running
Connect over SSH as azureuser, then confirm that all four units are active. idurar-firstboot.service is a one-shot unit that reports active after it completes successfully.
systemctl is-active mongod nginx idurar idurar-firstbootExpected output:
active active active activeCheck the installed release and confirm that the console answers:
cat /var/lib/sac/data/idurar-version curl -s -o /dev/null -w 'IDURAR web console: HTTP %{http_code}\n' http://127.0.0.1/Expected output:
idurar.tag=4.1.0 idurar.package_json=4.1.0 idurar.tarball_sha256=556e732f03f5292a6e0f0d7789660f4e9213b0fd0f5fe9d7d04504e07ec1afaa phantomjs.version=2.1.1 node.version=v22.23.1 IDURAR web console: HTTP 200Retrieve your per-VM credentials
The first boot generates every secret on this VM, and the secrets exist nowhere else. The image writes them to a root-only file.
sudo cat /root/idurar-credentials.txtOnly root can read the file. Confirm this yourself:
sudo stat -c '%n mode=%a owner=%U:%G' /root/idurar-credentials.txtExpected output:
/root/idurar-credentials.txt mode=600 owner=root:rootCopy the administrator email and password into your password manager now, then continue.
Sign in to the console
Browse to http://<your-vm-public-ip>/. The IDURAR sign-in page appears. Enter the idurar.admin.email and idurar.admin.password values from the credentials file.
You can verify the same credentials from the command line before you open a browser. The command reads the generated password straight from the credentials file, so there is nothing to paste:
ADMIN_EMAIL="$(sudo grep '^idurar.admin.email=' /root/idurar-credentials.txt | cut -d= -f2-)" ADMIN_PASSWORD="$(sudo grep '^idurar.admin.password=' /root/idurar-credentials.txt | cut -d= -f2-)" curl -s -X POST http://127.0.0.1/api/login \
-H 'Content-Type: application/json' \
-d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" \
| jq '{success, email: .result.email, role: .result.role}'Expected output:
{ "success": true, "email": "admin@example.com", "role": "owner" }After you sign in, you land on the dashboard, which summarizes invoices, quotes and customers for the current month.
Change the administrator address and password
The administrator email is a documented sample value, not a secret. Change it to a real address that you control, and set your own password. Use Settings in the console sidebar or the profile menu at the top right. Do this before you invite anyone else.
Add a customer and raise an invoice
The core workflow is Customers > Quote > Invoices > Payments. Add a customer from Customers > Add New Client. Then raise an invoice from Invoices > Add New Invoice: choose that customer, add line items, and select a tax rate.
You can do the same over the API. The following commands create a customer and an invoice, then read back the calculated totals:
ADMIN_EMAIL="$(sudo grep '^idurar.admin.email=' /root/idurar-credentials.txt | cut -d= -f2-)" ADMIN_PASSWORD="$(sudo grep '^idurar.admin.password=' /root/idurar-credentials.txt | cut -d= -f2-)" TOKEN="$(curl -s -X POST http://127.0.0.1/api/login -H 'Content-Type: application/json' \
-d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" | jq -r .result.token)" CLIENT_ID="$(curl -s -X POST http://127.0.0.1/api/client/create \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d '{"name":"Example Customer Ltd","country":"United Kingdom","email":"accounts@example.com"}' \
| jq -r .result._id)" curl -s -X POST http://127.0.0.1/api/invoice/create \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d "{\"client\":\"${CLIENT_ID}\",\"number\":5001,\"year\":$(date -u +%Y),\"status\":\"draft\",\"date\":\"$(date -u +%Y-%m-%d)\",\"expiredDate\":\"$(date -u -d '+30 days' +%Y-%m-%d)\",\"taxRate\":20,\"items\":[{\"itemName\":\"Consulting\",\"description\":\"Example line item\",\"quantity\":2,\"price\":500,\"total\":1000}]}" \
| jq '{success, number: .result.number, subTotal: .result.subTotal, taxTotal: .result.taxTotal, total: .result.total}'Expected output:
{ "success": true, "number": 5001, "subTotal": 1000, "taxTotal": 200, "total": 1200 }Download an invoice as a PDF
Open any invoice and choose Download PDF. The document is rendered on the VM by PhantomJS.
HTTP offers the same download. The download path is /download/invoice/invoice-<invoice-id>.pdf:
ADMIN_EMAIL="$(sudo grep '^idurar.admin.email=' /root/idurar-credentials.txt | cut -d= -f2-)" ADMIN_PASSWORD="$(sudo grep '^idurar.admin.password=' /root/idurar-credentials.txt | cut -d= -f2-)" TOKEN="$(curl -s -X POST http://127.0.0.1/api/login -H 'Content-Type: application/json' \
-d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" | jq -r .result.token)" INVOICE_ID="$(curl -s http://127.0.0.1/api/invoice/list -H "Authorization: Bearer ${TOKEN}" | jq -r '.result[0]._id')" curl -s -o /tmp/invoice.pdf -w 'invoice PDF: HTTP %{http_code}, %{size_download} bytes\n' \
"http://127.0.0.1/download/invoice/invoice-${INVOICE_ID}.pdf" file /tmp/invoice.pdfExpected output:
invoice PDF: HTTP 200, 70693 bytes /tmp/invoice.pdf: PDF document, version 1.4, 1 page(s)Understand the security model
Verify these three properties yourself.
cd /opt/idurar/backend && echo "administrator accounts: $(sudo node sac-admin.js count)" curl -s -o /dev/null -w 'upstream default credential -> HTTP %{http_code}\n' \
-X POST http://127.0.0.1/api/login -H 'Content-Type: application/json' \
-d '{"email":"admin@admin.com","password":"admin123"}' curl -s -o /dev/null -w 'anonymous API request -> HTTP %{http_code}\n' http://127.0.0.1/api/client/listExpected output:
administrator accounts: 1 upstream default credential -> HTTP 404 anonymous API request -> HTTP 401- One account, no default. The upstream project's setup routine creates
admin@admin.comwith the passwordadmin123. The build deletes that account and fails if any account survives, so it does not exist in this image. Your VM's single administrator was created on first boot with a random password. - No self-service sign-up. IDURAR exposes no registration route at all, so a passer-by cannot enroll on a public instance. The administrator adds new users from the console.
- The API and the database are private. The Express API listens on
127.0.0.1:8888and MongoDB on127.0.0.1:27017. Only nginx on port80is reachable from the network. Confirm with:
ss -tlnp 2>/dev/null | awk 'NR==1 || /:80 |:8888 |:27017 /' | sed 's/users:.*//'One caveat. Upstream mounts the PDF download route outside its authentication middleware, so anyone who knows an invoice's identifier can fetch that invoice's PDF without signing in. This is upstream behavior, not something this image introduces. Do not expose port 80 to the public internet without the TLS and access restrictions in Step 10.
Put your own domain and TLS in front
The image serves plain HTTP on port 80 so that it works immediately at any address. For anything beyond a trial, terminate TLS with your own certificate and restrict access with a network security group.
Point a DNS A record at the VM's public IP, allow 443/tcp in the NSG, then install a certificate. Replace the example values with your own:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain> -m <your-email> --agree-tos --redirectThe admin console calls the API on the same origin using relative paths, so you need no rebuild or reconfiguration when you move to a hostname or to HTTPS. It works at the new address.
Back up and restore
All business data lives in the idurar MongoDB database. Take a dump with the application credentials from the credentials file:
MONGO_APP_PASSWORD="$(sudo grep '^mongo.app.password=' /root/idurar-credentials.txt | cut -d= -f2-)" sudo mkdir -p /var/backups/idurar
sudo mongodump --host 127.0.0.1 --port 27017 \
-u idurar -p "${MONGO_APP_PASSWORD}" --authenticationDatabase idurar \
--db idurar --out /var/backups/idurar/$(date -u +%Y%m%d)Uploaded files (customer logos and attachments) live outside the database, so back them up too:
sudo mkdir -p /var/backups/idurar
sudo tar czf /var/backups/idurar/uploads-$(date -u +%Y%m%d).tar.gz \
-C /opt/idurar/backend/src/public uploadsTo restore, run mongorestore with the same credentials and untar the uploads back into place.
Connect a MongoDB client
MongoDB is deliberately not reachable from the network. To use a graphical client from your workstation, forward the port over SSH:
ssh -N -L 27017:127.0.0.1:27017 azureuser@<vm-ip>Then connect to mongodb://127.0.0.1:27017 using the mongo.admin.user and mongo.admin.password values from the credentials file, with admin as the authentication database.
Differences from a stock install
This image is the unmodified upstream release with one deliberate change, recorded here so that the image is auditable:
- The API is bound to the loopback interface. Upstream calls
app.listen(port)with no host argument, which binds every interface and leaves the API reachable on port8888from the network, bypassing nginx. The image adds aHOSTenvironment override that defaults to127.0.0.1. SettingHOST=0.0.0.0restores the upstream behavior.
The image does not change the following two items:
- The release is 4.1.0, not the newer 4.1.1 tag. Upstream's 4.1.1 release removed three data models that its own console still depends on. That silently removes the quotes, taxes and payment modes features from the API while the console continues to link to them. 4.1.0 is the newest release whose API and console agree, so that is what ships here.
- The seeded configuration is upstream's own. The image preserves the default tax rate and payment mode that the upstream setup routine creates. Only the seeded administrator account is removed.
Troubleshooting
The console loads but every action fails. Check that the API is running and reachable behind nginx:
systemctl is-active idurar curl -s -o /dev/null -w 'API through nginx: HTTP %{http_code}\n' http://127.0.0.1/api/client/list
sudo journalctl -u idurar.service -n 30 --no-pagerAn anonymous request to that endpoint that returns 401 is correct and healthy. It means the API is up and refusing unauthenticated access.
The application did not start after a rebuild or restore. idurar.service does not start until first-boot initialization has completed. This is deliberate, because it prevents the application from ever running with a sample secret. Confirm that the marker exists:
ls -l /var/lib/sac/data/idurar-bootstrap-ready /var/lib/sac/data/idurar-firstboot.done
sudo systemctl status idurar-firstboot.service --no-pager | head -20You lost the administrator password. Without email configured, there is no password reset, but you can create a new administrator directly on the VM:
cd /opt/idurar/backend
sudo SAC_ADMIN_EMAIL="you@example.com" SAC_ADMIN_PASSWORD="a-long-random-password" \
node sac-admin.js createThis command replaces every existing administrator with the one you specify and prints the resulting account count.
Support
24/7 technical support is included with this image. Email sales@secureanycloud.com with your Azure subscription ID and the VM name, and we respond within 24 hours.
Deploy on Azure
Launch IDURAR ERP CRM on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com