BHIMA 1.41.1
Overview
BHIMA (Basic Hospital Information Management Application, by IMA World Health and Third Culture Software) is a free and open source hospital information system for clinics and hospitals. It covers patient registration and visits, invoicing and cash, debtor groups and insurers, inventory and stock, and a full double-entry accounting system (OHADA chart of accounts, fiscal years, journals, reports).
This SecureAnyCloud AMI runs BHIMA 1.41.1 on Ubuntu 24.04 on Amazon EC2. It is one software version of the SecureAnyCloud Hardened EHRbase & GIS, Health and Research Platforms AMIs listing on AWS Marketplace, which you select when you subscribe and launch.
What you get:
- No demo database and no default logins. BHIMA's development database ships test patients and the
superuser/superuserlogin. This image ships an empty MySQL data directory instead. Before any public port opens, your instance's first boot creates its own database from BHIMA's release schema, one enterprise and project, and theadminaccount with a random 24-character password hashed with argon2.admin/adminandsuperuser/superuserare refused, and the web installer (/install) is closed. - Per-instance secrets, never on a command line. The admin password, the database password, BHIMA's session secret, the two session-store account passwords and the TLS key are generated on your instance. Nothing from the image build is reused. They live in files that only root can read (BHIMA's
.envis readable by root and thebhimagroup), never in a process's arguments or environment. - The current, verified release. BHIMA 1.41.1 is checked file for file against the official release archive, pinned by its checksum, with its lockfile pinned too. No source file is patched. Node.js 24.22.2 LTS comes from the official nodejs.org tarball, pinned by checksum.
- HTTPS from the first boot. nginx serves BHIMA on port 443 with a certificate generated on your instance. Port 80 redirects to HTTPS, and a request for an unknown host name gets no answer. BHIMA itself listens only on a local socket behind nginx.
- Sessions that end when you sign out. The session cookie is
Secure,HttpOnlyandSameSite=Strict. BHIMA also issues a 24-hour API token at sign-in that sign-out does not revoke. nginx strips that header, so only the session cookie is honored and signing out ends access. - A private, password-protected session store. Sessions live in memory only, in Valkey 7.2 (the open source Redis successor, replacing the
redis-serverthat BHIMA's documentation suggests). Valkey has no network listener at all. It listens on the socket/run/valkey/valkey.sock, which only thevalkeyandbhimaaccounts can open. Valkey's default (passwordless) user is off. BHIMA signs in as the accountbhimawith a password generated on your instance, and that account may run only the session-store commands on session keys. - A rate-limited sign-in. Sign-in is limited to 10 attempts a minute per address (after a burst of 10), in any spelling of the address. nginx sets the client address from the connection, so a forged
X-Forwarded-Forcannot dodge the limit. - Reports and sign-out protected from other sites. Report downloads and sign-out require same-site proof from the browser, so a link or image on another site cannot run a report or sign you out.
- Safe uploads. Patient documents and pictures are served only to signed-in users, with
nosniffand a sandboxing content security policy. Anything that is not a passive type (image or PDF) is sent as a download. - Report PDFs from a sandboxed Chrome that never calls out. BHIMA renders PDFs with Chrome. The image installs Chrome for Testing 157.0.8103.38 (pinned by checksum) instead of letting the npm package download one. Chrome's own sandbox stays on (under an AppArmor profile), and Chrome starts with a clean environment so it never sees BHIMA's secrets. It resolves no host name except
localhost, so a report never reaches the internet. - Hardened defaults. BHIMA runs as its own
bhimaaccount, which can write only/var/lib/bhima(its uploads and Chrome's profile). The code, configuration and Chrome are read-only to it. MySQL listens on 127.0.0.1 only, with no X Protocol, no binary or general log andLOCAL INFILEoff. Itsrootaccount signs in only through the socket as the operating-system root. BHIMA, nginx, MySQL, Valkey and the first-boot service are blocked from the instance metadata service, and the instance requires IMDSv2. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
- On the image: BHIMA 1.41.1, Node.js 24.22.2, Chrome for Testing 157.0.8103.38, MySQL 8.0, Valkey 7.2.13, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
- Defaults: default user
ubuntu, x86_64 architecture, recommended instance type m5.large.
Prerequisites
- An AWS account subscribed to the listing.
- An EC2 key pair.
- A VPC subnet with a route to the internet, or a private route you use for management.
- A security group that allows TCP 22 (SSH), TCP 443 (BHIMA) and TCP 80 (redirects to HTTPS) from the networks that should reach them. BHIMA holds patient and financial records, so keep port 22 to your own networks and open 443 only to the networks your staff work from.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select BHIMA 1.41.1 on Ubuntu 24.04 as the software version, pick your Region, and choose Launch through EC2.
Choose m5.large, your key pair and the security group described above.
To launch with the AWS CLI instead, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=bhima}]'First boot takes about a minute after the instance is running, because it builds BHIMA's database.
Connect to your instance
On BHIMA 1.41.1 on Ubuntu 24.04, the SSH user is ubuntu. Connect with the key pair you chose at launch:
ssh -i <your-key>.pem ubuntu@<public-ip-or-dns>Check the services
MySQL, Valkey, BHIMA and nginx should all report as active:
systemctl is-active mysql valkey-server bhima nginxactive active active activeOnly SSH, HTTP and HTTPS listen on the network. MySQL listens on 127.0.0.1. BHIMA and Valkey have no TCP listener at all, because each uses a local socket:
sudo ss -tlnH | awk '{print $4}' | sort -u0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 127.0.0.1:3306 127.0.0.53%lo:53 127.0.0.54:53 [::]:22 [::]:443 [::]:80Get your sign-in details
The credentials file holds the address BHIMA is served at (your instance's public DNS name by default), the admin user name and its password, and the project to choose at sign-in. All of these are generated on this instance:
sudo cat /root/bhima-credentials.txt# BHIMA on this instance (sac). Root-only (0600). Generated at first boot: 2026-11-07T14:02:11Z BHIMA_URL=https://ec2-54-172-234-205.compute-1.amazonaws.com/ BHIMA_ADMIN_USER=admin BHIMA_ADMIN_PASSWORD=<BHIMA_ADMIN_PASSWORD> BHIMA_PROJECT=Main Project
# The MySQL password of the bhima database user is in /etc/bhima-sac/db-password (root 0600) and in BHIMA's # /opt/bhima/bin/.env (root:bhima 0640); MySQL root is reachable only as the operating-system root (sudo mysql). # Change a password:
sudo bhima-sac-set-password [user] Change the hostname:
sudo bhima-sac-set-hostname <name>Sign in
Open BHIMA_URL in a browser. The certificate is self-signed, so the browser warns once. Continue to the site, and use Step 11 to replace the certificate with your own. Visiting the instance by its IP address redirects to the configured name.
BHIMA's interface starts in French. Choose your language from the small menu at the top right of the sign-in box. Your browser remembers the choice.
Sign in as admin with the password from the credentials file and the project Main Project. BHIMA opens on its home page, with the module tree on the left. The arrows at the bottom left open and close the tree.
A new instance has one enterprise, its project and the admin account only, so set up the basics first:
- Administration > Enterprise: set your organization's name, address and currency.
- Finance > Account Management: import BHIMA's default OHADA chart of accounts (or your own) from Menu.
- Finance > Fiscal Year: create the current fiscal year.
- Add your services (Administration), at least one debtor group (Finance) and your billable items (Inventory).
- Administration > Users: create an account for each member of staff with only the roles they need, and keep
adminfor administration.
Then register a patient (Hospital > Patient Registration), open a visit and raise an invoice (Finance > Patient Invoice). The patient and the invoice appear in the Patients Registry and the Invoice Registry, and in the reports.
Check HTTPS and the setup state
Port 80 redirects to HTTPS on the configured name:
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' http://127.0.0.1/301 https://ec2-54-172-234-205.compute-1.amazonaws.com/BHIMA's installer reports the instance as installed and refuses to run again, so nobody can take the instance over. Verify it:
H=$(sed -n 's/^set \$bhima_host "\(.*\)";$/\1/p' /etc/nginx/bhima-host.conf)
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/install"; echo
curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w 'second install: %{http_code}\n' -H 'Content-Type: application/json' -d '{}' "https://$H/install"{"isInstalled":true} second install: 400Your data
BHIMA keeps its records in the MySQL database bhima. It keeps uploaded patient documents and pictures in /var/lib/bhima/data/uploads. Back up both, for example:
sudo mysqldump --single-transaction --routines --triggers bhima | gzip > bhima-$(date +%F).sql.gz
sudo tar -C /var/lib/bhima/data -czf bhima-uploads-$(date +%F).tar.gz uploadsKeep backups private and encrypted, because they hold patient and financial records. The session store holds only sessions, in memory and never on disk, so it needs no backup.
Sessions and the session store
BHIMA 1.41.1 keeps a session until the user signs out (upstream turns off the session store's expiry). Sign out at the end of each working session, and use Step 13 to sign everyone out at once.
Valkey has no network listener. Its socket is open to the valkey and bhima accounts only, and even those clients must sign in:
sudo stat -c '%a %U:%G %n' /run/valkey /run/valkey/valkey.sock /etc/valkey/sac-bhima-users.acl /etc/bhima-sac/valkey-password
sudo -u ubuntu valkey-cli -s /run/valkey/valkey.sock PING 2>&1 | head -1 sudo -u bhima valkey-cli -s /run/valkey/valkey.sock PING 2>&1 | head -12750 valkey:bhima /run/valkey 770 valkey:bhima /run/valkey/valkey.sock 640 root:valkey /etc/valkey/sac-bhima-users.acl 600 root:root /etc/bhima-sac/valkey-password Could not connect to Valkey at /run/valkey/valkey.sock: Permission denied NOAUTH Authentication required.Valkey's account file holds only SHA-256 hashes of the two account passwords. The bhima account is BHIMA's own and may run session commands on session keys only. The bhima-admin account is root's, and bhima-sac-set-password uses it to find and remove sessions.
The passwords are in /etc/bhima-sac/valkey-password and valkey-admin-password, readable by root only. BHIMA receives its password as a systemd credential.
BHIMA 1.41.1 connects to its session store by host and port only, and it has no setting for a socket or a password. The image adds a small preload, /usr/local/lib/sac/bhima/valkey-client.js (started with node --require), that points BHIMA's client at the socket and signs it in as bhima. The preload lives outside BHIMA's release folder, which stays identical to the 1.41.1 release. Keep the preload when you update BHIMA (Step 10).
Known limits of BHIMA 1.41.1
These limits come from upstream BHIMA and have no fix in this release. The image's defaults reduce their reach.
- AngularJS 1.8.3 and Bootstrap 3.4.1. BHIMA's browser interface is built on AngularJS (end of life since January 2022), Bootstrap 3 and angular-sanitize. These carry moderate npm advisories without fixed versions. The two AngularJS advisories rated high (an
ng-srcsetregular-expression slowdown and an SCE resource-URL check) need features BHIMA does not use. Use a current browser and give staff accounts only the roles they need. - Other moderate and low advisories reported by
npm auditfor BHIMA's dependencies (for exampleuuidanddeepmerge) are in server-side code paths that BHIMA does not expose to unauthenticated users. The high-ratedbasic-ftp(used only by the npm package's own Chrome download, which the image skips) andimage-size(used only in code paths BHIMA never calls) are not reachable. - No server-side session expiry (Step 8). The API token that BHIMA issues at sign-in stays valid for 24 hours. nginx strips it, so it cannot be used through nginx.
Updating BHIMA
BHIMA is installed from its release archive in /opt/bhima/bin, owned by root, and runs from there. Before you move to a newer release, take a snapshot and a database backup (Step 7), then follow BHIMA's upgrade notes for that release.
Unpack the new archive in place of the old one and keep /opt/bhima/bin/.env. Run npm ci --omit=dev --ignore-scripts with PUPPETEER_SKIP_DOWNLOAD=1, run the release's database migration, then restart BHIMA.
Keep the preload (Step 8). BHIMA's systemd unit starts it, so a release that keeps BHIMA's session client keeps working. Check the release notes for a newer Chrome requirement.
Keep the operating system patched with sudo apt-get update && sudo apt-get upgrade. MySQL, Valkey and nginx are Ubuntu packages, and unattended security upgrades are already on.
Your own DNS name and certificate
Point a DNS record at the instance, then set the name BHIMA is served at. This command mints a new self-signed certificate for the name, pins it in nginx (the instance's IP addresses redirect to it) and records it in the credentials file:
sudo bhima-sac-set-hostname <your-domain>To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running bhima-sac-set-hostname again replaces it with a self-signed certificate.
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/bhima.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/bhima.key
sudo nginx -t && sudo systemctl reload nginxOnce browsers trust the certificate, you can also add an HSTS header in nginx. The image does not send one, because browsers ignore HSTS from a site whose certificate they do not trust.
Behind a load balancer or CloudFront: terminate TLS on the load balancer and forward to port 443 on the instance with the configured host name. nginx always uses the connection's address as the client address, so with a proxy in front, every request counts against the proxy's sign-in budget. If that limit is too tight, raise it in /etc/nginx/conf.d/sac-bhima-guard.conf.
Security checks
Check that the admin password signs in over HTTPS, that the session works, that sign-out ends it (the old cookie is refused) and that a wrong password is refused:
sudo bhima-sac-cred-roundtripBHIMA_LOGIN_OK https 200 200 401 401Without a session, BHIMA's API answers nothing, in any spelling of the address. The upstream default logins are refused:
H=$(sed -n 's/^set \$bhima_host "\(.*\)";$/\1/p' /etc/nginx/bhima-host.conf) R=(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null) for p in /patients /PATIENTS /patients/ /users/1 /reports/finance/invoices; do "${R[@]}" -w "$p %{http_code}\n" "https://$H$p"; done "${R[@]}" -w 'superuser/superuser %{http_code}\n' -H 'Content-Type: application/json' -d '{"username":"superuser","password":"superuser","project":1}' "https://$H/auth/login" "${R[@]}" -w 'unknown host %{http_code}\n' -H 'Host: other.example' https://127.0.0.1/ ; echo/patients 401 /PATIENTS 401 /patients/ 401 /users/1 401 /reports/finance/invoices 403 superuser/superuser 401 unknown host 000The code 000 means nginx closed the connection without an answer. A 403 on /reports comes from nginx itself: report and sign-out requests must come from the BHIMA page, with a matching Origin or Referer, before they reach BHIMA.
BHIMA, nginx, MySQL and Valkey are blocked from the instance metadata service. systemd may list the four addresses in a different order:
systemctl show -p IPAddressDeny bhima nginx mysql valkey-serverIPAddressDeny=::ffff:169.254.169.254/128 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=::ffff:169.254.169.254/128 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=::ffff:169.254.169.254/128 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=::ffff:169.254.169.254/128 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32The credentials and passwords are readable by root only. BHIMA's .env is readable by root and the bhima group, and the code belongs to root:
sudo stat -c '%a %U:%G %n' /root/bhima-credentials.txt /etc/bhima-sac/db-password /etc/bhima-sac/valkey-admin-password /opt/bhima/bin/.env /opt/bhima/bin/server/app.js /var/lib/bhima600 root:root /root/bhima-credentials.txt 600 root:root /etc/bhima-sac/db-password 600 root:root /etc/bhima-sac/valkey-admin-password 640 root:bhima /opt/bhima/bin/.env 644 root:root /opt/bhima/bin/server/app.js 700 bhima:bhima /var/lib/bhimaPasswords and signing everyone out
bhima-sac-set-password gives a BHIMA user (by default admin) a new random password hashed with argon2, signs out every session in the session store and records the password in /root/bhima-credentials.txt.
The command first checks that the session store answers. If it does not, the command changes nothing and says so. If any session survives, the command fails with an error.
To choose your own password, run the command with the password on standard input (12 to 96 letters and digits):
sudo bhima-sac-set-password printf '%s\n' '<new-password>' | sudo bhima-sac-set-password admin --stdinbhima-sac-set-password: the password of 'admin' was changed and every session signed out (4 revoked, 0 remain)Server components
These are the components on the instance and where each one lives:
- BHIMA 1.41.1 release (owned by root): /opt/bhima/bin
- BHIMA settings (database password, session secret; root:bhima 0640): /opt/bhima/bin/.env
- Uploads and Chrome's profile (owned by bhima): /var/lib/bhima
- BHIMA service: /etc/systemd/system/bhima.service
- Session store client preload: /usr/local/lib/sac/bhima/valkey-client.js
- Valkey settings (included last from valkey.conf) and account file: /etc/valkey/sac-bhima.conf, /etc/valkey/sac-bhima-users.acl
- Passwords (root only): /etc/bhima-sac/
- Chrome for Testing and its wrapper: /opt/bhima/chrome, /usr/local/lib/sac/bhima-chrome
- Database (MySQL datadir) and settings: /var/lib/mysql, /etc/mysql/mysql.conf.d/99-sac-bhima.cnf
- nginx site, request limits and cross-site rules: /etc/nginx/sites-available/sac-bhima, /etc/nginx/conf.d/sac-bhima-guard.conf, /etc/nginx/conf.d/sac-xsite-guard.conf
- Certificate and key: /etc/nginx/ssl/
- First boot and helpers: /usr/local/sbin/bhima-firstboot, bhima-sac-set-hostname, bhima-sac-set-password, bhima-sac-cred-roundtrip
- License and image notes: /usr/share/doc/bhima-sac/
- Credentials: /root/bhima-credentials.txt (mode 0600)
Security recommendations
- Allow port 22 in the security group from your own networks only, and port 443 only from the networks your staff use.
- Keep the admin password secret (Step 13). Give each member of staff their own account with the fewest roles they need, and sign out at the end of each session.
- Use your own DNS name and a certificate your browsers trust (Step 11).
- Back up the database and the uploads regularly, and encrypt the backups (Step 7).
- Keep BHIMA on the newest release (Step 10) and keep the operating system patched.
Support and licensing
BHIMA is free software under the GNU General Public License version 2. A copy is at /usr/share/doc/bhima-sac/LICENSE.bhima. The bundled libraries, Chrome for Testing, Node.js, MySQL, Valkey and nginx carry their own open source licenses. There is no per-user or per-CPU license fee.
SecureAnyCloud builds and supports this image. BHIMA is developed by IMA World Health and Third Culture Software, and SecureAnyCloud is not affiliated with them.
- Email: sales@secureanycloud.com
Deploy on AWS
Launch BHIMA 1.41.1 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com