Server
Open mSupply server is a component of the Open mSupply system. The server:
- Hosts the server web interface and exposes RESTful and GraphQL APIs for open mSupply data.
- Synchronises with central servers which implement
v5of the mSupply sync API. - Exposes a dynamic plugin system for customising and extending functionality.
- Can act as a remote or central omSupply server, see Synchronisation documentation
Quick Start
Remote server can use sqlite or postgres, quick start guide is for sqlite flavour.
Dependencies
N.B. The version of rust used by open mSupply as of July 2025 is 1.88, so, once you've installed rust in the guides below, set up your environment to use that version. You can do that by running rustup install 1.88 and then rustup default 1.88.
When changing to newer rust version please make sure to update docker build container as per this commit.
Windows
- Follow Microsoft's Rust installation guide
- Install perl
- For building the windows binary, you'll need to install the Bonjour Windows SDK and configure the environment variable
BONJOUR_SDK_HOMEto point to the installation location. This is required for the dns-sd implementation on windows, used for server discovery.
Mac
-
Follow the Rust installation guide.
-
For M1/M2/M3 Mac:
brew install libpq and add the following to ~/.cargo/config.toml
[env]
MACOSX_DEPLOYMENT_TARGET = "10.12"
[target.aarch64-apple-darwin]
rustflags = "-L /opt/homebrew/opt/libpq/lib"Ubuntu
- Follow the Rust installation guide.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- After a fresh
rustupinstallation start a new bash to make env variable available - Install packages (e.g. needed to install/compile openssl-sys):
sudo apt install make gcc pkg-config libavahi-compat-libdnssd-dev libpq-devSet up sync with mSupply central
Remote server data is configured through mSupply central server, when the app first starts it's expected to initialise from mSupply.
Set up Open mSupply remote site in mSupply
- Ensure you have mSupply set up locally
- In Admin > Preferences > General, ensure
Synchronisation is activeis selected - In Special > Synchronisation
- Open (or create) the site for our Open mSupply instance
- Does it have a hardware ID already? If so, refresh the hardware ID so it doesn't have one.
- Initialise your Open mSupply instance - you can do this two ways:
- Via the UI (this may be the easier option when you are switching between different APIs):
- After starting the server & client, you should see an initialisation screen
- Enter the site details from mSupply
- Via YAML configuration:
- In your Open mSupply repo, under
server/configurationcopy theexample.yamltolocal.yaml, and uncomment the contents of the file. Under thesyncconfig, ensure theusernameis set to the site name from mSupply (i.e.remote) - Your Open mSupply instance should sync with mSupply automatically when you start the server
- In your Open mSupply repo, under
- Via the UI (this may be the easier option when you are switching between different APIs):
- After the initial sync, you generally shouldn't need mSupply running to run Open mSupply
OR: Run without mSupply central
Instead of initialising from mSupply, there is also a cli option to initialise from previously exported initialisation:
cargo run --bin remote_server_cli -- initialise-from-export -n [export name]
Where [export name] is name of exported data in data/ folder
# example
cargo run --bin remote_server_cli -- initialise-from-export -n reference1
Above will create a SQLite database file in your current working directory (typically server/), using the name from configuration/*.yaml (by default omsupply-database.sqlite), and populate it with data. Towards the end of the CLI output a user:password list is printed (those users can be used to log in via the client/API).
NOTE:
initialise-from-exportcurrently emits a large number of warnings (see https://github.com/msupply-foundation/open-msupply/issues/10241). The command should still complete and print a list of username/passwords. Those credentials are also listed indata/reference1/users.txt.
Start the server
Now we can start server with
cargo run
NOTE: make sure that sync configurations in
configuration/*.yamlfiles are commented out if running without mSupply Central, otherwise you may get an error stating that the database and yaml sync configurations differ (in which case, the remote server will try to contact central server)
Explore API available on http://localhost:8000/graphql with build in playground or try online graphiql explorer
Open mSupply Central and Remote
Open mSupply server can be launched in both modes, this is controlled via Site is open mSupply central server configuration in legacy mSupply site settings, more info in Sync Docs and Integration Test Docs.
From version 2.0 omSupply would require both legacy and omSupply central server for full configuration/synchronisation. To start both omSupply central and omSupply remote:
- Create two sites as per above "Set up sync with mSupply central" instructions
- Configure one site to be central server by checking
Site is open mSupply central serverand entering the URL with which remote sites can reach this site in the fieldThis site url cargo runtwice but change port, database and sync settings in yaml file or overwrite with env variables
For example, two sites running locally from the same repo, central and test, for central site Site is open mSupply central server is checked and This site url is http://localhost:2055.
Comment out all sync settings in yaml and can start central with APP__SERVER__PORT=2055 APP__DATABASE__DATABASE_NAME="central_test" cargo run front end would be started with yarn start -- -- --env API_HOST='http://localhost:2055' --port 3005 (--port is for webpack port), and then start test with cargo run and yarn && yarn start-local from respective folders. The first site would be initialised with central site credentials first, and second sites with test credentials, test site would sync with both legacy mSupply and omSupply central server (this central site), and central site would synchronise with legacy mSupply server only
Start server in watch mode
Sometimes it's nice to have your dev server automatically rebuild and restart on changes.
You'll need to install cargo-make and cargo-watch globally:
cargo install cargo-make cargo-watch
Then, to start the server in watch mode:
cargo make watch
Note: watch mode may not always be a part of your desired workflow - particularly when you are making lots of backend changes, it's another competitor for the build directory file lock on every save (alongside tests, rust-analyzer...) and Rust compilation isn't known for its speediness 😁
It's great for cases such as doing frontend work, where you want the backend to refresh as you switch/pull branches, or when making minor backend changes. Or you can play around with debounced re-compile times, with the
cargo-watch--delayflag.
Start with feature flags
Feature flags can be used to enable/disable certain features. Mostly we use them to hide features in the that are not ready for production. See Feature Flags hook for currently available flags.
To enable a feature, easiest way is to set the variable in your configuration yaml file, e.g.
features:
example_feature: true
See Config section for more info on yaml configurations.
Run with postgres
Dependencies
When using Postgres, Postgres 12 or higher is required.
Windows
- Install PostgreSQL.
- Locate your
PostgresSQLinstallation directory (e.g.C:\Program Files\PostgreSQL\14\). - Update
PathandPQ_LIB_DIRenvironment variables:
> $env:PQ_LIB_DIR='C:\Program Files\PostgreSQL\14\lib'
> $env:Path+='C:\Program Files\PostgreSQL\14\lib;C:\Program Files\PostgreSQL\14\bin'
- To persist
PathandPQ_LIB_DIRfor all future sessions, paste the following into a powershell terminal (requires administrator privileges):
# CAUTION: this is irreversible!
Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $env:Path
Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PQ_LIB_DIR -Value $env:PQ_LIB_DIRMac
- Download and install via installers
Ubuntu
- Install Postgres:
sudo apt install postgresqlOptional
- Install pgAdmin (see deployment instructions if using the Docker image)
Postgres rust feature
Remote server by default will run with sqlite database (sqlite rust feature), postgres can be turned on with postgres feature.
i.e. to run without mSupply central, as per above
- Make sure that postgres credentials are correct in
configuration/*.yaml(database will be automatically created)
cargo run --bin remote_server_cli --features postgres -- initialise-from-export -n reference1
cargo run --features postgresDatabase CLI
You can manually create and migrate database with the following
- Settings in
configurations/*.yamlwill be used for credentials and database name
# postgres
cargo run --bin remote_server_cli --features postgres -- initialise-database
# sqlite
cargo run --bin remote_server_cli -- initialise-databaseSharing SQLite Database files
When using sqlite, open-mSupply enables a feature called Write Ahead Log (WAL), this uses a separate file to improve concurrent access to the data.
If you want to ensure all your changes have been written to the main sqlite database file, you may need to run the VACUUM command against your database.
sqlite3 omsupply-database 'VACUUM;'
Configs
note: yaml configurations are likely to be deprecated to .env, thus documentations is limited for .yaml.
In configurations folder you'll find .yaml config files, there is base, local (will overwrite/expand base in dev mode), production (will overwrite/expand other configs when APP\_\_ENVIRONMENT=production ).
Config files can be selected with the --config-path argument. When this argument is not provided configuration will default to local.yaml/production.yaml as per above. When providing a file path, the code expects a base.yaml file to exist at the same directory level as the chosen file.
cargo run -- --config-path configurations/alternate_file.yaml
You can use env variable to overwrite any configurations, can use dot notation with __ (two underscore) to specify nested value. Env vars configuration overrides start with APP__.
# example, will overwrite sync.url config in yaml
APP__SYNC__URL='http://localhost:8001' cargo runExport initialisation
If you have mSupply central running and want to export initialisation
- Note sync credentials from
configurations/*.yamlor env vars will be used
cargo run --bin remote_server_cli -- export-initialisation -n [name of export] -u [users]
# example
cargo run --bin remote_server_cli -- export-initialisation -n 'reference2' -u 'user1:password1,user2:password2'
# password in configurations/.*yaml is hashed, can use -p option to specify unhashed password
cargo run --bin remote_server_cli -- export-initialisation -n 'reference2' -u 'user1:password1,user2:password2' -p 'syncpassword'SSL/https
- To enable ssl place the
key.pemandcert.pemfiles into theapp_data/certsdirectory. - Update the server.host variable in the configuration if needed
- In production (-release build) server must be running with ssl
Use a self signed cert, e.g. for testing
# Ensure certs directory exits
mkdir -p app_data/certs
# Testing cert for CN=localhost
openssl req -x509 -newkey rsa:4096 -nodes -keyout app_data/certs/key.pem -out app_data/certs/cert.pem -days 365 -subj '/CN=localhost'Test
Devs should run both postgres and sqlite tests before publishing a PR. The CI uses cargo nextest which is an alternative test runner tailored for use with CI. By default it runs crates in parallel which should speed up test execution times.
More info: https://nexte.st/
- To run all tests:
# Install nextest runner
cargo install cargo-nextest --locked
# Use sqlite (sqlite is default feature)
cargo nextest run
# Use postgres
cargo nextest run --features postgres
- To run email tests: Start mailhog (or similar email capture service). For install instructions visit: https://github.com/mailhog/MailHog
cargo test --features=email-tests --package service --lib -- email_test --nocapture
- To run sync integration test
Note, to speed-up tests database templates are used (Sqlite + Postrgres), e.g. to reuse fully migrated databases from previous tests.
To disable this you can set the environment variable MSUPPLY_NO_TEST_DB_TEMPLATE=true.
However, in general this should not be needed but might be useful if you suspect a bug in the test template code.
Building docs
Docs are built via github action, but can build local version with docker: how to build docs locally
CORS settings
By default remote-server limits Cross-Origin Resource Sharing to the origins configured in the server section of the configuration yaml. This is a security mechanism to reduce the risk of a malicious site accessing an authenticated connection with mSupply. Rust enforces the allowed origins in requests, even if the browser doesn't, by returning a 400 error when the Origin isn't specified in a request, or if doesn't match one of origins configured in cors_origins.
Set the cors_origins section of the yaml to include any URLs you want to access Open mSupply's GraphQL API from this includes the url for the omsupply-client you are using. e.g. local.yaml
server:
port: 8000
cors_origins: [http://localhost:3003, https://youwebserver:yourport]
In development mode (if not built with --release) cors is set to permissive (server will return allow origin = requesting origin)
server:
port: 8000
cors_origins: [http://localhost:3003, https://youwebserver:yourport]Serving front end
Server will serve front end files from (client/packages/host/dist), if the client was not build and the folder is empty, server will return an error message: Cannot find index.html. See https://github.com/openmsupply/open-msupply#serving-front-end.
You can build front end by running yarn build from client directory in the root of the project. After that if you run the server you can navigate to http://localhost:port to see this feature in action.
When app is built in production mode (with build --release) static files will be embedded in the binary. To build, run yarn build command from the root of repository. This will build the client application and then build the release version of the server, bundling in the client so that it can be hosted.
Cli
Some common operations are available via cli remote_server_cli, the --help flag should give a detailed explanation of how to use cli. Here are example of all of the currently available commands. note: configurations from configurations/*.yaml or env vars will be used when running cli commands.
note: All of the cli commands are meant for development purposes, some commands are dangerous to run in production
# overall help
cargo run --bin remote_server_cli -- --help
# help for an action
cargo run --bin remote_server_cli -- initialise-from-export --help
# exports graphql schema to schema.graphql file
cargo run --bin remote_server_cli -- export-graphql-schema
# initialise database (creates or replaces existing database and initialises schema)
cargo run --bin remote_server_cli -- initialise-database
# by default all commands will run with sqlite database, use --features postgres to use postgres database (not applicable to export-initialisation or export-graphql-schema action)
cargo run --bin remote_server_cli --features postgres -- initialise-database
# export initialisation data from mSupply central to `data/export_name` folder (IMPORTANT: Should not be used on large data files, as single JSON format is not suited for large set of data)
cargo run --bin remote_server_cli -- export-initialisation -n 'export_name' -u 'user1:password1,user2:password2' -p 'sync_password'
# initialise database from initialisation export (will replace current data), and in this case -r flag will attempt to advance all historic date and date/times forward.
cargo run --bin remote_server_cli -- initialise-from-export -n 'export_name' -r
# initialise from mSupply central (will replace current data)
cargo run --bin remote_server_cli -- initialise-from-central -u 'user1:password1'
# attempt to refresh dates (advance them forward, see --help)
cargo run --bin remote_server_cli -- refresh-dates
# See README.md link below
cargo run --bin remote_server_cli -- backup
cargo run --bin remote_server_cli -- restore -b D2024_08_22T05_05_16 -sConfig check tool
This tool is mostly intended for support, to confirm everything is configured correctly. It checks things like the database connection, and connecting to central servers for sync.
You can run the tool in either the cli mode or as a GUI. The postgreSQL and SQLite versions of each are shown below.
CLI
cargo run --bin remote_server_cli -- test-connection -u username -p password
When running the cli command, normal debug level logging to console is suppressed as this can get verbose. If you want to view all the log info, you can specify an -l parameter and specify the debug level:
cargo run --bin remote_server_cli -- test-connection -u username -p password -l infoGUI
cargo run --bin test_connection
or build and run the binary. Pass in --features postgres to run the postgres version.
Backup and Restore
Discovery
DNS-SD is available for all targets except for Android (for Android DNS-SD is toggled at runtime and is done in native java code).
We also start another graphql server with initialisationStatus query endpoint, in http mode with permissive cors.
This allows site information (initialised/site) to be presented during discovery.
Logging
By default, the server logs to console with a logging level of Info
You can configure this, to log to a file, for example, with a rollover of log files based on file size.
See the example.yaml file for the available options.
Directory structure
An overview of how files are organised in the server repo is shown below, with annotations as noted. The files have been split in this way, grouped in crates, partly to improve build times - as well as a logical organisation of grouped concerns.
server
├─ android (hoisting for the android implementation)
├─ cli
├─ configuration (runtime configuration files)
├─ data (contains reference data which can be used by the cli to initialise the database)
├─ docs
├─ graphql
│ ├─ batch_mutations (batch mutations are grouped here)
│ ├─ core (the loaders, filters, errors, pagination and test helpers)
│ ├─ general (mutations and queries which are shared or small enough to not require separate implementation)
│ ├─ types (each database table has its types defined in a file)
│ ├─ [data type]
│ │ ├─ src
│ │ │ ├─ lib.rs (queries are in here, if not in a separate file, as below)
│ │ │ ├─ [data type]_queries.rs
│ │ │ └─ mutations
│ │ └─ test_output
├─ report_builder
├─ repository
│ ├─ migrations
│ ├─ src
│ │ ├─ db_diesel (definitions for the database objects)
│ │ └─ mock
│ └─ test_output
├─ scripts
├─ server (includes the logging, front-end hosting, certificates, DNS-SD discovery, configuration)
├─ service (these functions provide an intermediary between GraphQL and the repository and houses most of the business logic)
├─ target
├─ test_output
├─ util
└─ windows (windows service hosting for the server)
The batch_mutations case is a special one - the crate is fairly slow to compile, so has been split out. There are also some dependency issues, as it combines other objects, such as invoice and invoice_line.