Oh
Applications Azure

Open HRMS on Ubuntu 24.04 on Azure User Guide

| Product: Open HRMS on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Open HRMS on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Open HRMS is the open source human resource management suite from Cybrosys Technologies, delivered as a set of modules built on Odoo 18 Community Edition. It covers the whole employee lifecycle in one system: employee records and documents, contracts and working shifts, attendance with regularisation, leave and holiday approval, community payroll with salary rules and payslips, appraisals, loans and salary advances, gratuity settlement, insurance, custody of company assets, disciplinary tracking, resignation and transfer workflows, service requests, and an HR dashboard that brings the whole picture together.

The cloudimg image ships Odoo 18 Community (LGPL-3, installed from the project's own dated release, pinned and SHA-256 verified) with 33 Open HRMS modules (LGPL-3 and AGPL-3) already installed and their schema migrated, on box PostgreSQL 16, and nginx terminating TLS as the single public listener. Odoo and PostgreSQL bind to the loopback interface only. The database manager is blocked at the front door, the database is built without demo data, and everything unique is minted per VM on first boot: the PostgreSQL password, the Odoo master password, a self signed TLS certificate and the administrator password. Backed by 24/7 cloudimg support.

Odoo is a trademark of Odoo S.A. Open HRMS is a product name of Cybrosys Technologies. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by either. It ships the free and open source software unmodified; the corresponding sources are Odoo Community (https://github.com/odoo/odoo, branch 18.0) and Open HRMS (https://github.com/CybroOdoo/OpenHRMS, branch 18.0).

The postgresql, nginx, openhrms-tls, odoo and openhrms-firstboot units all active, Odoo reporting 18.0.20260909, 33 Open HRMS modules on disk and 133 modules installed in the database

What is included:

  • Odoo 18 Community Edition — the project's own dated release, pinned by URL and SHA-256 and installed from a single package file, so no third party APT source is left on the VM
  • 33 Open HRMS modules — from the project's 18.0 line, pinned to an exact upstream commit and shipped unmodified, with the schema already migrated
  • PostgreSQL 16 — the application database, bound to loopback with no host port published
  • nginx — the single public listener, terminating TLS, with HTTP to HTTPS redirect and correct proxy headers
  • First boot secret generation — database password, Odoo master password, TLS certificate and administrator password, all unique to each VM
  • A bundled self test — signs in as the per instance administrator, creates an employee record, reads it back, finds it by search and deletes it, proving the suite really works end to end

Prerequisites

  • An Azure subscription with permission to create virtual machines
  • An SSH key pair for administrative access
  • A network security group allowing inbound TCP 22 (SSH) and TCP 443 (HTTPS) from your own address ranges
  • Standard_D2s_v3 (2 vCPU, 8 GB RAM) or larger. Odoo runs two worker processes alongside PostgreSQL on the same VM, so 8 GB is the practical floor; choose more memory and a larger disk as your headcount and attachment volume grow

Step 1: Deploy from the Azure Portal

  1. Open the Azure Marketplace and search for Open HRMS on Ubuntu 24.04 LTS by cloudimg.
  2. Select Create, then choose your subscription, resource group and region.
  3. Pick a VM size of Standard_D2s_v3 or larger.
  4. Under Administrator account, select SSH public key and supply your public key.
  5. Under Inbound port rules, allow SSH (22) and HTTPS (443).
  6. Select Review + create, then Create.

Step 2: Deploy from the Azure CLI

az group create --name openhrms-rg --location eastus
az vm create \
  --resource-group openhrms-rg \
  --name openhrms-vm \
  --image cloudimg:openhrms-ubuntu-24-04:default:latest \
  --size Standard_D2s_v3 \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

az vm open-port --resource-group openhrms-rg --name openhrms-vm --port 443 --priority 1010

First boot takes a couple of minutes: the VM generates its own PostgreSQL password, Odoo master password, TLS certificate and administrator password, sets the administrator credential through Odoo's own password hasher, starts the application, and then proves the whole stack with the bundled self test before it reports ready.

Step 3: Connect over SSH

ssh azureuser@<public-ip>

Step 4: Confirm the services are running

systemctl is-active postgresql nginx openhrms-tls odoo openhrms-firstboot

Expected output:

active
active
active
active
active

openhrms-tls is a one shot unit that mints this VM's TLS certificate before nginx starts, and openhrms-firstboot is the one shot unit that generated every secret. Both report active after they have completed.

Step 5: Check the versions and the installed module set

dpkg-query -W -f='${Version}\n' odoo
ls /opt/openhrms/addons | grep -vE '^(LICENSE|README.md)$' | wc -l
sudo -u postgres psql -d openhrms -tAc "select count(*) from ir_module_module where state='installed'"

Expected output:

18.0.20260909
33
133

33 Open HRMS modules are staged on disk, and 133 Odoo modules are installed in the database — the Open HRMS set plus every Odoo Community module they depend on.

Three modules from the upstream repository are deliberately not shipped, and the image asserts their absence at build time:

Module Why it is not shipped
ent_uae_wps_report Declares the Odoo Proprietary License (OPL-1), which forbids redistribution, and is the only module in the set that depends on Odoo Enterprise addons. The LGPL-3 module uae_wps_report provides the same UAE WPS report on Community payroll and is included.
oh_hr_zk_attendance Integrates physical ZKTeco biometric terminals through the PyPI packages zklib (last released 2015) and pyzk (last released 2019), both abandoned and predating Python 3.12. It cannot function without the hardware on your LAN.
hr_company_policy Its browser side template targets an element the Open HRMS dashboard no longer renders at this release, which breaks the dashboard outright for every user. Excluded rather than patched, so the image keeps shipping upstream code unmodified.

You can install any of them yourself from the upstream repository if your deployment needs them.

Step 6: Retrieve the per instance credentials

Every secret on this VM was generated on this VM. Read them as root:

sudo cat /root/openhrms-credentials.txt

Expected output (your values will differ — every VM generates its own):

# Open HRMS on Ubuntu 24.04 — Per-VM Instance Info
# Generated: <generation timestamp>
#
# Every secret below was generated on THIS virtual machine at first boot. None was baked into
# the image and no two cloudimg VMs share any of them. Keep this file secret.
#
OPENHRMS_ADMIN_USER=admin
OPENHRMS_ADMIN_PASSWORD=************************
OPENHRMS_URL=https://<your VM's public IP>/
OPENHRMS_DB_NAME=openhrms

The per VM credentials file is root only at mode 600, the Odoo configuration is 640 root:odoo, and the configuration shows the database manager disabled, Odoo bound to loopback and proxy mode on

The Odoo master password and the PostgreSQL password are not in that file — they live in /etc/odoo/odoo.conf, readable only by root and the odoo service account:

sudo stat -c '%a %U:%G %n' /root/openhrms-credentials.txt /etc/odoo/odoo.conf

Expected output:

600 root:root /root/openhrms-credentials.txt
640 root:odoo /etc/odoo/odoo.conf

Step 7: Review the security posture

Only three TCP ports face the network. Odoo's HTTP worker (8069), its websocket worker (8072) and PostgreSQL (5432) are bound to loopback and cannot be reached from outside the VM:

ss -tlnH | awk '{print $4}' | sort -u

Expected output:

0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:5432
127.0.0.1:8069
127.0.0.1:8072
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
[::]:443
[::]:80

The database manager is blocked. Odoo's built in manager will happily serve its Create / Duplicate / Backup / Restore forms to an unauthenticated visitor even when database listing is switched off, so this image blocks the whole /web/database path at nginx as well as setting list_db = False:

for U in /healthz /web/health /web/login /web/database/manager /web/database/create /web/database/selector; do
  printf '%-28s %s\n' "$U" "$(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1$U)"
done

Expected output:

/healthz                     200
/web/health                  200
/web/login                   200
/web/database/manager        404
/web/database/create         404
/web/database/selector       404

Plain HTTP only redirects:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/

Expected output:

301

Off box listeners are SSH 22 and nginx 80 and 443 only, with Odoo and PostgreSQL on loopback, the health endpoints returning 200, every database manager path returning 404 and plain HTTP returning 301

Step 8: Prove the whole stack with the bundled self test

sudo /usr/local/bin/openhrms-selftest

This is a real feature round trip, not a page load. It checks the TLS front door and the HTTP redirect, confirms the login page and its stylesheet and script bundles are served with the right content types, confirms the database manager refuses to serve, rejects a deliberately wrong password, signs in with this VM's own administrator credential, reads all 33 Open HRMS modules back as installed, resolves the Open HRMS dashboard, then creates an employee record, reads it back field by field, finds it by name search and deletes it, checking the employee count returns to where it started. It finishes by asserting the exact set of network facing ports.

Expected output:

OK openhrms self-test passed: healthz 200, :80 301, login page + text/css + javascript served, /web/health pass, database manager refuses to serve, wrong password rejected, per-VM admin authenticated, all 33 Open HRMS modules installed (both excluded modules absent), dashboard action resolves, hr.employee create/read/search/delete round-trip OK with the count back to 1, backend asset bundle compiled (1185944 bytes of real CSS), anonymous RPC refused, exposed ports exactly {22,80,443}, Odoo 8069/8072 + PostgreSQL 5432 loopback-only

The bundled self test passing every check, including the blocked database manager, the rejected wrong password, all 33 modules installed and a full employee create, read, search and delete round trip

Step 9: Sign in

Open https://<your VM's public IP>/ in a browser. The certificate is self signed and generated on your VM, so your browser will warn once; accept it, or replace the certificate as described in Step 14.

Sign in with the username and password from /root/openhrms-credentials.txt.

The Open HRMS sign in page served over TLS

The sign in page is wrapped in Odoo's public website layout with placeholder content, because the Website module is a dependency of the Open HRMS Employee Background Verification module. You can edit or unpublish those public pages from the Website app once you are signed in.

Step 10: The Open HRMS dashboard

Signing in lands you on the Open HRMS dashboard, the suite's home view. It draws your own figures from the database: payslip, timesheet and contract counts, the broad factor absence score, a check in control, and panels for attendance, leave, expenses and projects, alongside upcoming birthdays, events and announcements. Further down are the leave and skill analyses, leave request and allocation counts, job applications, departments, and the monthly join, resign and attrition charts.

The Open HRMS dashboard drawing payslip, timesheet, contract and broad factor tiles, attendance, leave, expense and project panels, and the upcoming birthday, event and announcement cards

Step 11: Add your first employee

  1. Open the Employees app from the app menu.
  2. Select New, enter the person's name and job title, and fill in the work email and department.
  3. Save.

The employee form is Odoo's own, extended by Open HRMS: extra tabs for Insurance and Employee History, smart buttons for Disciplinary Action and Announcements, and menu entries for Document Templates, Legal Actions, Services and Loans & Advances.

An employee record open in the HR form view, showing the Open HRMS additions: Insurance and Employee History tabs, Disciplinary Action and Announcements counters, and the Document Templates, Legal Actions, Services, Insurance and Loans and Advances menus

The image ships with a single employee record, Administrator, which Odoo's own HR module creates and links to the administrator account. There is no demo data of any kind: no sample company beyond the default, no invented employees, contracts or payslips.

Step 12: Review the installed Open HRMS modules

Open the Apps app, clear the default Apps filter, and search for Open HRMS. Every module in the result set is already installed — none of them shows an Activate button.

The Apps view filtered to Module: Open HRMS, showing thirty Open HRMS modules, none of which offers an Activate button because all of them are already installed

You can confirm the same thing from the shell:

sudo -u postgres psql -d openhrms -tAc "select count(*) from ir_module_module where state='installed' and (name like 'ohrms\_%' or name like 'oh\_%' or name like 'hrms\_%')"

Expected output:

12

That counts only the modules whose technical name carries an Open HRMS prefix; the rest of the suite uses hr_-prefixed names shared with Odoo's own HR modules, which is why the full staged count in Step 5 is 33.

Step 13: Day to day operations

Working through the suite:

  • Departments and job positions — Employees → Configuration
  • Working schedules and shifts — Employees → Configuration → Working Schedules, and the Open HRMS Employee Shift module for shift rosters
  • Attendance — the Attendances app, with Open HRMS Attendance Regularization for correcting missed check ins
  • Leave — the Time Off app, with Open HRMS Leave Multi-Level Approval for multi stage approval chains and Leave Request Aliasing for requests by email
  • Payroll — the Payroll app provided by the Open HRMS community payroll modules: salary structures, salary rules, contracts and payslips
  • Loans and advances — Open HRMS Loan Management and Advance Salary, with the accounting bridge in Loan Accounting
  • Appraisals, custody, insurance, resignation, transfer and legal actions — each has its own menu once you are signed in

Step 14: Replace the TLS certificate

The shipped certificate is self signed and generated on your VM. For production, point a DNS name at the VM and install a CA signed certificate. Place the certificate and key at /etc/nginx/tls/openhrms.crt and /etc/nginx/tls/openhrms.key, keep the key mode 0600, then reload nginx.

If you use Let's Encrypt, install certbot and issue the certificate against your own domain:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

After changing the hostname customers use, update Odoo's own base URL so generated links point at it. Sign in as the administrator, enable the developer tools, then open Settings → Technical → System Parameters and set web.base.url to your HTTPS URL. The image sets web.base.url.freeze to True deliberately, so Odoo will not silently overwrite that value with whatever host an administrator last signed in from.

Step 15: Back up the database

The whole application state is the PostgreSQL database plus Odoo's filestore. Back up both:

sudo -u postgres pg_dump -Fc openhrms > /var/backups/openhrms-$(date +%F).dump
sudo tar czf /var/backups/openhrms-filestore-$(date +%F).tar.gz -C /var/lib/odoo filestore

Odoo's own browser based backup tool is not available on this image, because the database manager it lives in is blocked at the front door. pg_dump is the supported path and is what you should schedule.

Step 16: Logs and troubleshooting

sudo tail -20 /var/log/odoo/odoo-server.log
sudo journalctl -u odoo --no-pager | tail -20

The first boot log records everything that was generated on this VM:

sudo tail -20 /var/log/cloudimg-firstboot.log

If the web interface is unreachable, work outwards: check systemctl is-active odoo nginx postgresql, confirm Odoo is answering on loopback with curl -sf http://127.0.0.1:8069/web/health, then check that your network security group allows inbound 443. Re-running sudo /usr/local/bin/openhrms-selftest at any time will tell you exactly which layer is broken.

Security notes

  • No credential is baked into the image. It ships with every user's password column empty, no /etc/odoo/odoo.conf at all, the PostgreSQL role password reset to a value that is generated and immediately discarded, and no TLS key. Odoo itself is gated by systemd and refuses to start until first boot has written this VM's own configuration, so there is no window in which the appliance is reachable with a shared secret.
  • Odoo and PostgreSQL never face the network. nginx on 443 is the only application listener; port 80 exists solely to redirect.
  • The database manager is blocked. Nobody can list, create, duplicate, drop, back up or restore a database from a browser, with or without the master password.
  • Self registration is not available — Odoo's sign up flow is not enabled on this image, so accounts are created by an administrator from Settings → Users.
  • Unattended security upgrades remain enabled, exactly as stock Ubuntu, so the VM keeps patching itself.
  • The certificate is self signed per VM. Replace it with a CA signed certificate before putting the system in front of staff.

Licensing

Odoo Community Edition is licensed under the LGPL version 3. The Open HRMS modules shipped here are licensed under the LGPL version 3 (28 modules) and the GNU Affero General Public License v3 (5 modules), and are shipped unmodified from the upstream repository at a pinned commit. There is no per user or per employee fee for the software. The cloudimg charge covers packaging, security hardening, patching, image maintenance and 24/7 support.

The provenance of everything in the image, including the exact Odoo package and checksum and the exact Open HRMS commit, is recorded on the VM:

cat /usr/share/doc/openhrms/PROVENANCE

cloudimg is not affiliated with, endorsed by or sponsored by Odoo S.A. or Cybrosys Technologies. The Odoo and Open HRMS names are used only to identify the software this image ships.

Support

24/7 cloudimg support with a guaranteed 24 hour response SLA. Contact support through the Azure Marketplace listing or at https://www.cloudimg.co.uk/.