Overview
Patient records, visits, scheduling, documents and billing in one system, shaped around how Malaysian physiotherapy practices work: MyKad numbers, insurance panels and guarantee letters included.
Two ways to install
PhysioSuite installs in one of two ways: on two servers, an application server and a data server joined by a private network, or on one server that holds both. The same command starts either, and the setup page asks where the data lives.
Two servers
The application server runs PhysioSuite and keeps no records. The data server keeps the records, the documents and their nightly backup: a NAS, a PC or another server. The two talk only over an encrypted private network that PhysioSuite runs itself.
Choose it to keep patient records off the machine that staff reach over the internet.
One server
One machine runs PhysioSuite and keeps the records, the documents and their nightly backup, with no private network to set up and one web address instead of two.
Choose it where the records may be kept on that machine. Set up the off-site copy too: a backup on the same disk does not survive the loss of the server.
Either way, one command on the server that runs PhysioSuite checks this release and starts a one-time setup page, which does the rest.
Requirements
A licence from Astrea
The registry account and the licence key, which let the server download PhysioSuite. Licence enquiries: support@astrealab.ai.
Web addresses
PhysioSuite's own, with a DNS record pointing at the application server. With two servers, a second for their private network, pointing at the same server.
A named first administrator
A person's own sign-in name. Shared names such as admin are refused, as the audit log records
who did what.
Later, and not needed to install: off-site storage, any S3-compatible bucket, for an off-site copy of the backups.
The application server
The machine that runs PhysioSuite, wherever the practice chooses to run it. With two servers, it keeps no records.
| Minimum | Recommended | |
|---|---|---|
| System | 64-bit Linux with Docker Engine | Ubuntu Server 24.04 or 26.04 LTS, or Debian 12 or 13, where the installer can install Docker itself |
| Processor | Intel or AMD, 64-bit (x86_64) | The same |
| Cores | 1 | 2 |
| Memory | 2 GB | 4 GB |
| Disk | 10 GB, with 5 GB free for PhysioSuite | 20 GB, SSD |
| Docker | Docker Engine 24.0 and Docker Compose 2.20.0 or later | The versions PhysioSuite is tested on (below) |
| Ports | TCP 80 and 443 from the internet, or your existing reverse proxy (nginx, Apache, Caddy) forwarding to PhysioSuite; UDP 3478 | The same |
| Access | SSH, as a user who may use sudo | The same |
The data server
The machine that keeps the records and their nightly backup: a NAS with Docker, a PC, a virtual machine or another server, each installed the same way.
| Minimum | Recommended | |
|---|---|---|
| System | 64-bit Linux with Docker Engine | A NAS with mirrored or RAID disks, or Ubuntu Server LTS or Debian |
| Processor | Intel, AMD or ARM, 64-bit (x86_64 or aarch64) | The same |
| Cores | 2 | 4 |
| Memory | 4 GB | 8 GB |
| Disk | 10 GB free, plus twice the size of the practice's documents, on the machine's own disks; the database never on a network share | The same, on mirrored or RAID disks; SSD for the database where there is a choice |
| Docker | Docker Engine 24.0 and Docker Compose 2.20.0 or later | The same as the application server |
| Ports | None from the internet. It connects out to the application server on TCP 443 and UDP 3478 | The same |
| Access | SSH from the office network, as an administrator who may use sudo | The same |
| Power | Always on: never asleep or switched off at night, when the backup runs | On a UPS |
Both on one server
Where the records may stay on the application server ("This server" on the setup page), one machine holds both.
| Minimum | Recommended | |
|---|---|---|
| Processor | Intel or AMD, 64-bit (x86_64) | The same |
| Cores | 2 | 4 |
| Memory | 4 GB | 8 GB |
| Disk | The application server's and the data server's together | The same, SSD |
| Docker | Docker Engine 24.0 and Docker Compose 2.25.0 or later | The same |
| Ports | TCP 80 and 443 from the internet, or your existing reverse proxy; no UDP 3478, as there is no private network | The same |
Below the minimum memory or cores, the installer warns and carries on. It refuses less than 5 GB of free disk, and a machine it cannot run on: one that is not Linux or not 64-bit, ARM for the application server, Docker Desktop, Docker installed from Snap, and Podman. A machine that sleeps or is switched off at night, and a database service run by a hosting company, are not supported.
Tested on Ubuntu 26.04 LTS with Docker Engine 29.9.1 and Docker Compose 5.6.0. Where Docker is missing on Debian or Ubuntu, the installer offers to install Docker Engine 29 and Docker Compose 5 from Docker's own repository, never on a NAS. The figures above were measured in Astrea's own tests, with a practice's scale of invented data.
What the installer sets up
For your IT team: each part PhysioSuite runs, on which server, what it does, its image in this release, and what it listens on. Each part runs in its own Docker container, from an image pinned for this release; this table is made from the release's own files.
The reverse proxy: PhysioSuite's own, or yours
PhysioSuite's built-in reverse proxy is Traefik. Where TCP ports 80 and 443 are free on the application server, it takes them: it receives every visit over HTTPS, gets and renews the certificates from Let's Encrypt, and passes each request on to the part that answers it. Where your existing reverse proxy (nginx, Apache, Caddy or Traefik) already holds 80 and 443, PhysioSuite leaves it in charge: the installer prints the settings to add to it, filled in for your server, and Traefik then listens only on two local ports behind it. Your reverse proxy keeps its other sites, and holds the certificates for PhysioSuite's addresses. Either way, UDP 3478 stays open directly, for the private network's relay.
| Part | What it does | Image in v0.1.1 | Listens on |
|---|---|---|---|
| The application server | |||
| Reverse proxy (Traefik) | PhysioSuite's built-in reverse proxy. It receives every visit over HTTPS, gets and renews the certificates from Let's Encrypt, sends plain HTTP on to HTTPS, and passes each request to the screens, the API, the setup page while it runs, or Headscale. | traefik:v3.7.17 | TCP 80 and 443 from the internet; UDP 3478 for the private network's relay. Behind your existing reverse proxy: TCP 11000 and 11001 on a local address instead of TCP 80 and 443. |
| Private network: coordination (Headscale) | Decides which machines may join the private network, and relays its traffic when a direct path is blocked. Only PhysioSuite's two servers join. | headscale/headscale:v0.29.7 | No port of its own: reached through the reverse proxy at the private network's address. |
| Private network: this server's end (Tailscale) | The application server's end of the encrypted tunnel (WireGuard) to the data server. | tailscale/tailscale:v1.104.4 | No port on the host: it connects out. |
| PhysioSuite's API | PhysioSuite's back end (Django). It reaches the database through the private network and keeps no records on this server. | physiosuite/backend:v0.1.1 | No port on the host: reached through the reverse proxy. |
| PhysioSuite's screens | The pages staff open in their browser, served by nginx. | physiosuite/frontend:v0.1.1 | No port on the host: reached through the reverse proxy. |
| The setup page | The one-time setup page, only while the install runs; it is removed when the install finishes. | python:3.13.18-slim-trixie | No port on the host: reached through the reverse proxy at /setup while it runs. |
| The data server | |||
| Private network: this server's end (Tailscale) | The data server's end of the encrypted tunnel to the application server. | tailscale/tailscale:v1.104.4 | No port on the host: it connects out. |
| Database (PostgreSQL) | Keeps PhysioSuite's records. | postgres:18.6-trixie | No port on the host or the office network: only inside the private network. |
| Nightly database copy (pg_dump) | Copies the database every night with pg_dump, from the database's own image, into one file. | postgres:18.6-trixie | No port: reaches the database inside the private network. |
| Backups (restic) | Keeps encrypted restore points of the database copy and the documents store, on the data server. | restic/restic:0.19.1 | No network at all. |
| Both servers | |||
| Docker Engine and Docker Compose | Run each part above in its own container. The installer uses the server's own Docker; on Debian or Ubuntu without it, it offers to install Docker's own packages, and installs them only on a clear yes. Never on a NAS. | Engine 24.0 and Compose 2.20.0 or later; installed: Engine 29, Compose 5 | No port. |
With one server holding both, the data server's parts run on the application server: the private
network is not started, its relay port is not opened, and the database answers on an internal Docker network
only. The documents store is a folder, not a program: on the data server, shared to the application server and
marked once with sudo physiosuite mark-store.
Install
This page is for PhysioSuite v0.1.1. The newest release is always at get.astrealab.ai/physiosuite/.
On the application server, as a user who may use sudo:
$ curl -fsSL https://get.astrealab.ai/physiosuite/v0.1.1/install.sh -o install.sh
$ sudo bash install.sh
The first line downloads a short script; read it before running it if you wish:
install.sh. Another release is installed with
sudo bash install.sh --version vX.Y.Z.
What happens next
- The script downloads PhysioSuite v0.1.1, checks Astrea's signature and the archive's checksum, and stops if either check fails. Nothing runs before both pass.
- It checks the server, chooses PhysioSuite's built-in reverse proxy or finds your existing one, and asks one question: PhysioSuite's web address.
- It prints a link and a one-time setup code. Open the link in a browser. The code works for 60 minutes and
five tries, in one browser only. Closing the SSH window does not stop the setup: in a new one,
sudo physiosuite setup statusshows where it is, andsudo physiosuite setup logs -ffollows its lines. - The setup page asks the rest in seven steps, each checked before the next: this installation, the reverse proxy, backups, the data server, modules and the first administrator, a review, and the install. With two servers, the data server joins in the fourth step, with one command over SSH, a NAS included.
- When the install finishes, the setup page closes and its code is deleted. The first administrator signs in at PhysioSuite's address.
Releases
| Release | Date | Page |
|---|---|---|
| v0.1.1 | 14 November 2026 | v0.1.1 |
| v0.1.0 | 13 November 2026 | v0.1.0 |
What is new in v0.1.1
Added
- The setup page asks for the receipt's document type (RECEIPT by default) beside the invoice's, and the installer writes it to the application's settings. A self-pay visit's receipt is then left out of the check made before a visit is sent to submissions or invoiced, as the invoice is.
Changed
- pypdf 7.0.0, which fills AIA's assessment letters (from 6.21.4).
- The screens' test tools: vitest 5.1.0 and jsdom 31.0.0. Nothing changes on screen.
Fixed
- Signing a release with no passphrase for the release key now says so in plain words, instead of stopping with gpg's "Inappropriate ioctl for device".
Files of v0.1.1
| File | Size | SHA-256 |
|---|---|---|
| physiosuite-v0.1.1.tar.gz | 280 KB | 4890f82762e4435ec65754cb897cba3824ea707d8257a723d29dffe33496d693 |
| install.sh | 8 KB | 9904158db406726cfacb565f86ba70e119f2eae45e8fd650ee423ded922a1127 |
| astrea-release-key.asc | 421 bytes | d4882f1e7fe9b46362bf6a2ea7200c72b8078d75f8be9a72c8e024ff37d81276 |
Verify
The script does this on its own. To repeat it by hand, as Ubuntu's own downloads are checked:
$ v=v0.1.1; base=https://get.astrealab.ai/physiosuite/$v
$ curl -fsSL -O "$base/SHA256SUMS" -O "$base/SHA256SUMS.gpg" \
-O "$base/physiosuite-$v.tar.gz" -O "$base/astrea-release-key.asc"
$ gpg --show-keys astrea-release-key.asc
$ gpg --dearmor < astrea-release-key.asc > astrea-release.gpg
$ gpgv --keyring ./astrea-release.gpg SHA256SUMS.gpg SHA256SUMS
$ sha256sum --check --ignore-missing SHA256SUMS
The key's fingerprint must read:
2238 0CCB 5687 2AD0 5807 ABC0 1ADA C65F 0D4F 070B
On Debian 13, where gpgv is not installed, use
sqv --keyring astrea-release.gpg --signature-file SHA256SUMS.gpg SHA256SUMS instead.