Install on Ubuntu
This guide was last updated for Ubuntu 24.04, although it should work for most recent versions.
Prerequisites
First, update and upgrade the system.
sudo apt-get update
sudo apt-get upgrade
sudo reboot
Install postgres
Add the PostgreSQL Apt Repository (see PostgreSQL Apt Repository docs)
# Configure the Apt repository
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
# Install Postgres 16
sudo apt install postgresql-16 postgresql-client-16
Start postgres
sudo pg_ctlcluster 16 main start
Start postgres client
sudo -u postgres psql
Create a "medplum" user:
CREATE USER medplum WITH PASSWORD 'medplum';
Create a "medplum" database:
CREATE DATABASE medplum;
GRANT ALL PRIVILEGES ON DATABASE medplum TO medplum;
\c medplum
GRANT ALL ON SCHEMA public TO medplum;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO medplum;
Create a "medplum_test" database:
CREATE DATABASE medplum_test;
GRANT ALL PRIVILEGES ON DATABASE medplum_test TO medplum;
\c medplum_test
GRANT ALL ON SCHEMA public TO medplum;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO medplum;
Exit psql
exit
Install redis
sudo apt-get install redis-server
Open the redis config file
sudo vi /etc/redis/redis.conf
Uncomment the "requirepass" line and set a password
requirepass medplum
Restart redis
sudo systemctl restart redis-server
Install Node.js
Add the Node.js v22.x Ubuntu repository:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
Install Node.js
sudo apt-get install nodejs
Build Medplum
Clone the Medplum repository
git clone https://github.com/medplum/medplum.git
cd medplum
Install dependencies
npm ci
Build the server, app, and necessary dependencies
npm run build:fast
Start Medplum server
These are abbreviated instructions. For full details, see Run the stack
Start the server
in development mode:
cd packages/server
npm run dev
You should now be able to access the Medplum server at http://localhost:8103/healthcheck.
Start Medplum app
This command runs Medplum app using the Vite Dev server. While this is convenient for development and testing, it has two significant limitations:
- The Vite dev server is designed for development, not production use. It serves files inefficiently and will provide an inferior experience for end users.
- The Medplum app requires several modern browser features that are only available in a 'secure context' (HTTPS), including essential cryptography features. These features will not be available when accessing the app via plain HTTP.
If you plan to access the app and API from other devices on your network, we recommend proceeding to the optional SSL/nginx setup instructions below. This will provide the secure context required for all Medplum features to function correctly.
In another terminal, start the app
in development mode:
cd packages/app
npm run dev
You should now be able to access the Medplum app at http://localhost:3000.
Optional: Nginx
While these instructions demonstrate a basic nginx setup, our primary recommendation is deploying Medplum to AWS using CDK or other infrastructure-as-code tools for production environments. This guide serves as an educational example of how the components work together and could be a viable solution for some deployments.
While this configuration is not officially supported at present, we welcome community interest - if you would like to sponsor work on publishing an official deb image and APT repository, we would love to work with you!
Overview
To run Medplum securely, you should use SSL/TLS via reverse proxy such as nginx.
To do this, you will need to:
- Install Nginx
- Install Certbot
- Setup SSL
- Add Nginx sites
Before you begin, please identify the domain names you will use for the app and api. For this example, we will use app.example.com
and api.example.com
.
Update Medplum server settings
Navigate to your server
directory:
cd medplum/packages/server
Update the medplum.config.json
file with your new domain:
{
"baseUrl": "https://api.example.com"
// ...
}
Restart the server. If you intend to run the server continuously and survive SSH disconnects, you may consider using nohup
:
nohup npm run dev > server.log 2>&1 &
Update Medplum app settings
In the terminal that is running app
, you now must update the .env
file with your new domain:
echo "MEDPLUM_BASE_URL=https://api.example.com" > .env
Build the app. This will generate a new version of the app in the dist
directory:
npm run build
Start the "preview" server:
nohup npx vite preview > app.log 2>&1 &
Install Nginx and Certbot
Install nginx and Certbot:
sudo apt-get install nginx certbot python3-certbot-nginx
Setup SSL
Before setting up SSL, make sure your domains point to your server and Nginx is running:
sudo systemctl start nginx
sudo systemctl enable nginx
Get SSL certificates from Let's Encrypt for both domains:
sudo certbot --nginx -d app.example.com
sudo certbot --nginx -d api.example.com
Add Nginx site for app
For the app, we will proxy requests to the Vite preview server running on port 4173.
Create an app
config file such as /etc/nginx/sites-available/app.example.com
:
# /etc/nginx/sites-available/app.example.com
server {
listen 80;
listen [::]:80;
server_name app.example.com;
# Redirect HTTP to HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:4173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Add Nginx site for api
For the API server, we will proxy requests to the Node.js server running on port 8103.
Create a api
config file such as /etc/nginx/sites-available/api.example.com
:
# /etc/nginx/sites-available/api.example.com
server {
listen 80;
listen [::]:80;
server_name api.example.com;
# Redirect HTTP to HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:8103;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Enable the sites
Enable the site:
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/
Remove the default site:
sudo rm /etc/nginx/sites-enabled/default
Test the configuration:
sudo nginx -t
If the test is successful, reload Nginx:
sudo systemctl reload nginx
Verify the setup
You should now be able to view the API server healthcheck at https://api.example.com/healthcheck
And the app at https://app.example.com