This project holds the build configuration for the OpenMRS 3.0 reference application, found on https://dev3.openmrs.org and https://o3.openmrs.org.
docker compose upor to enable SSL,
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upThe OpenMRS 3.x UI is accessible at http://localhost/openmrs/spa or https://localhost/openmrs/spa
OpenMRS Legacy UI is accessible at http://localhost/openmrs or https://localhost/openmrs
For production deployments with HTTPS/SSL certificates:
SSL_MODE=prod \
CERT_WEB_DOMAINS=your-domain.com \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upSee the SSL/HTTPS Configuration section for detailed setup instructions.
This distribution consists of four images:
- db - This is just the standard MariaDB image supplied to use as a database
- backend - This image is the OpenMRS backend. It is built from the main Dockerfile included in the root of the project and
based on the core OpenMRS Docker file. Additional contents for this image are drawn from the
distrosub-directory which includes a full Initializer configuration for the reference application intended as a starting point. - frontend - This image is a simple nginx container that embeds the 3.x frontend, including the modules described in the
frontend/spa-assemble-config.jsonfile. - gateway - This image is an nginx reverse proxy that sits in front of the
backendandfrontendcontainers and provides a common interface to both. This helps mitigate CORS issues.
When running with SSL enabled (using docker-compose.ssl.yml), an additional service is included:
- certbot - This image is used for generating and renewing SSL certificates (Let's Encrypt or self-signed)
The application can be run with SSL/HTTPS support for both development and production environments.
For local development with HTTPS, simply run with the SSL compose file:
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upThis will:
- Automatically generate self-signed certificates for
localhostand127.0.0.1 - Configure nginx to use HTTPS on port 443
- Redirect HTTP (port 80) to HTTPS
The application will be accessible at:
Note: Your browser will show a security warning for self-signed certificates. This is expected - click "Advanced" and proceed to the site.
For production deployments with valid SSL certificates from Let's Encrypt:
SSL_MODE=prod \
CERT_WEB_DOMAINS=example.com \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upConfiguration options:
SSL_MODE=prod- Use Let's Encrypt certificates (required)CERT_WEB_DOMAINS- Your domain name(s), comma-separated (e.g.,example.com,www.example.com)CERT_CONTACT_EMAIL- Email for Let's Encrypt notificationsSSL_STAGING=true- (Optional) Use Let's Encrypt staging environment for testing
The certbot container will:
- Create a temporary certificate to allow nginx to start
- Wait for nginx to be ready
- Request a real Let's Encrypt certificate via ACME HTTP-01 challenge
- Reload nginx with the real certificate
- Run a renewal daemon that checks for renewal every 12 hours
Important: Ensure your domain's DNS is correctly configured to point to your server before starting, as Let's Encrypt needs to verify domain ownership via HTTP.
To test the SSL setup without hitting Let's Encrypt rate limits:
SSL_MODE=prod \
SSL_STAGING=true \
CERT_WEB_DOMAINS=example.com \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upStaging certificates won't be trusted by browsers but allow you to verify the setup works correctly.
Let's Encrypt offers different certificate profiles with varying validity periods:
| Profile | Validity | Use Case |
|---|---|---|
classic |
90 days (default) | Standard certificates |
tlsserver |
45 days | Shorter validity for improved security |
shortlived |
6 days | Required for IP address certificates |
To request a specific profile, use the CERT_PROFILE environment variable:
# Request 45-day certificates
SSL_MODE=prod \
CERT_PROFILE=tlsserver \
CERT_WEB_DOMAINS=example.com \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upNote: Let's Encrypt is transitioning all certificates to 45-day validity by 2028. Using the tlsserver profile allows you to opt-in to shorter certificates now.
Let's Encrypt now supports issuing certificates for publicly-addressable IP addresses. These certificates must use the shortlived profile (6-day validity).
# Certificate for an IP address (shortlived profile auto-selected)
SSL_MODE=prod \
CERT_WEB_DOMAINS=203.0.113.50 \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upImportant notes for IP address certificates:
- The IP address must be publicly addressable (not private IPs like 192.168.x.x or 10.x.x.x)
- The
shortlivedprofile is automatically selected when an IP address is detected - Certificates are valid for approximately 6 days and renew automatically
- IPv6 addresses are also supported
You can also mix domain names and IP addresses:
SSL_MODE=prod \
CERT_WEB_DOMAINS=example.com,203.0.113.50 \
[email protected] \
docker compose -f docker-compose.yml -f docker-compose.ssl.yml upWhen any IP address is included, the shortlived profile is required and will be automatically enforced.
While certificates renew automatically in production mode, you can manually force renewal if needed.
If the certbot container is running (prod mode):
# Force renewal
docker compose -f docker-compose.yml -f docker-compose.ssl.yml exec certbot \
certbot renew --force-renewal --webroot -w /var/www/certbot
# Reload nginx to pick up new certificates
docker compose -f docker-compose.yml -f docker-compose.ssl.yml exec gateway \
nginx -s reloadIf certbot container has stopped or for one-off renewal:
# Run certbot in one-off mode (override entrypoint to run certbot directly)
docker compose -f docker-compose.yml -f docker-compose.ssl.yml run --rm \
--entrypoint certbot certbot \
renew --force-renewal --webroot -w /var/www/certbot
# Reload nginx
docker compose -f docker-compose.yml -f docker-compose.ssl.yml exec gateway \
nginx -s reloadCheck certificate expiration:
# If certbot container is running
docker compose -f docker-compose.yml -f docker-compose.ssl.yml exec certbot \
certbot certificates
# If certbot container is stopped
docker compose -f docker-compose.yml -f docker-compose.ssl.yml run --rm \
--entrypoint certbot certbot \
certificates| Variable | Default | Description |
|---|---|---|
SSL_MODE |
dev |
dev for self-signed certificates, prod for Let's Encrypt |
SSL_STAGING |
false |
Use Let's Encrypt staging environment (set to true for testing) |
CERT_WEB_DOMAINS |
localhost,127.0.0.1 |
Comma-separated list of domain names or IP addresses |
CERT_WEB_DOMAIN_COMMON_NAME |
(first domain) | Override the primary domain name |
CERT_CONTACT_EMAIL |
(empty) | Email for Let's Encrypt notifications (required in prod mode) |
CERT_RSA_KEY_SIZE |
4096 |
RSA key size for certificates |
CERT_PROFILE |
(empty) | Certificate profile: classic (90 days), tlsserver (45 days), or shortlived (6 days). Auto-set to shortlived for IP addresses |
This project uses the Initializer module to configure metadata for this project. The Initializer configuration can be found in the configuration subfolder of the distro folder. Any files added to this will be automatically included as part of the metadata for the RefApp.
Eventually, we would like to split this metadata into two packages:
openmrs-core, which will contain all the metadata necessary to run OpenMRSopenmrs-demo, which will include all of the sample data we use to run the RefApp
The openmrs-core package will eventually be a standard part of the distribution, with the openmrs-demo
provided as an optional add-on. Most data in this configuration should be regarded as demo data. We
anticipate that implementation-specific metadata will replace data in the openmrs-demo package,
though they may use that metadata as a starting point for that customization.
To help us keep track of things, we ask that you suffix any files you add with either
-core_demo for files that should be part of the demo package and -core_data for
those that should be part of the core package. For example, a form named test_form.json would become
test_core-core_demo.json.
Frontend configuration can be found in frontend/config-core_demo.json.
Thanks!