Skip to content

Jmevorach/openemr-on-openshift

 
 

Repository files navigation

OpenEMR on OpenShift Developer Sandbox

OpenEMR Version PHP Version MariaDB Version Redis Version CentOS Stream Container Registry License ONC Certified Build and Push OpenEMR

Production-ready deployment of OpenEMR 8.0.0 on Red Hat OpenShift Developer Sandbox using a custom CentOS 10 Stream container with PHP 8.5 from Remi's repository.

Overview

This project provides a complete containerized deployment of OpenEMR (Open-source Electronic Medical Records) on Red Hat OpenShift Developer Sandbox.

🚀 Technology Stack

Component Version Purpose
OpenEMR 8.0.0 Electronic Medical Records System
PHP 8.5 Runtime (Remi's Repository)
MariaDB 11.8 Database Backend
Redis 8 Alpine Session Storage & Cache
nginx 1.26 Web Server
CentOS Stream 10 Base Container OS
Node.js 22 LTS Frontend Build (build-time only)

✨ Key Features

  • Custom OpenEMR Container: Built on CentOS 10 Stream with Remi's PHP 8.5
  • Redis Session Storage: Redis 8 Alpine for improved performance and scalability
  • MariaDB 11.8: Latest Fedora MariaDB for robust database backend
  • Developer Sandbox Ready: Optimized for Developer Sandbox storage and resource constraints
  • OpenShift Native: Designed for OpenShift SCCs and security constraints
  • Production Ready: Includes health checks, resource limits, and monitoring
  • HIPAA Considerations: Encrypted transport, audit logging capabilities
  • Auto-Configuration: Zero-touch deployment with automated setup
  • US Core 8.0 / USCDI v5: Latest FHIR interoperability standards

Note: This deployment is configured for OpenShift Developer Sandbox which uses AWS EBS storage (ReadWriteOnce only). OpenEMR runs as a single replica, suitable for development, demo, and small practice environments.

Why OpenEMR?

OpenEMR stands as the world's most popular open-source electronic health records and medical practice management solution, and for good reason:

Certified Excellence: OpenEMR 7.0 achieved ONC 2015 Cures Update Certification, meeting rigorous U.S. federal standards for interoperability, security, and clinical quality measures. This certification enables providers to participate in Quality Payment Programs (QPP/MIPS) and demonstrates commitment to healthcare standards.

Global Impact at Scale: With over 100,000 medical providers serving more than 200 million patients across 100+ countries, OpenEMR has proven its reliability in diverse healthcare settings. The software is translated into 36 languages and downloaded 2,500+ times monthly, reflecting its worldwide trust and adoption.

True Interoperability: OpenEMR implements modern healthcare standards including FHIR APIs, SMART on FHIR, OAuth2, CCDA, Direct messaging, and Clinical Quality Measures (eCQMs). This extensive interoperability enables seamless integration with labs, hospitals, health information exchanges, and third-party applications—eliminating data silos and vendor lock-in.

Cost-Effective Freedom: As genuinely free and open-source software (no licensing fees, ever), OpenEMR provides an economically sustainable alternative to proprietary systems. Healthcare organizations maintain complete control over their data and infrastructure, with the freedom to customize, extend, or migrate without vendor restrictions or hidden costs.

Community-Driven Innovation: Developed since 2002 by physicians for physicians, OpenEMR benefits from contributions by hundreds of developers and support from 40+ professional companies. This vibrant ecosystem ensures continuous improvement, long-term sustainability, and responsive support options ranging from community forums to professional vendors.

Healthcare Without Boundaries: OpenEMR's mission ensures that quality healthcare technology remains accessible regardless of practice size, geographic location, or economic resources. This democratization of healthcare IT particularly benefits underserved communities, small practices, and international healthcare providers who were left behind by commercial EHR systems.

Whether you're a solo practitioner, a community health center, or a large healthcare system, OpenEMR provides enterprise-grade capabilities without enterprise-grade costs—proving that world-class healthcare software should be accessible to all.

Architecture

┌─────────────────────────────────────────────┐
│          OpenShift Route (HTTPS)            │
│    openemr-openemr.apps.sandbox.xxx.xxx     │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│         OpenEMR Service (ClusterIP)         │
│                Port 8080                    │
└─────────────────┬───────────────────────────┘
                  │
        ┌─────────▼──────────┐
        │  OpenEMR Pod       │
        │  (single replica)  │
        │  nginx + PHP-FPM   │
        └────┬───────────┬───┘
             │           │
    ┌────────▼───┐  ┌───▼──────────┐
    │ Redis Svc  │  │ MariaDB Svc  │
    │ Port 6379  │  │ Port 3306    │
    └────┬───────┘  └───┬──────────┘
         │              │
    ┌────▼────────┐ ┌──▼───────────┐
    │ Redis Pod   │ │ MariaDB      │
    │ (sessions)  │ │ StatefulSet  │
    └────┬────────┘ └──┬───────────┘
         │             │
    ┌────▼────────┐ ┌─▼────────────┐
    │ Redis PVC   │ │ Database PVC │
    │ (RWO - 1Gi) │ │ (RWO - 5Gi)  │
    └─────────────┘ └──────────────┘
         
        ┌─────────────────┐
        │  Documents PVC  │
        │  (RWO - 10Gi)   │
        │  gp3 storage    │
        └─────────────────┘

Developer Sandbox Constraints:

  • AWS EBS storage (gp3) provides ReadWriteOnce (RWO) volumes only
  • Single OpenEMR replica due to RWO storage limitation
  • Resource quotas: ~768Mi RAM and ~500m CPU per container
  • Total storage: 16Gi (5Gi database + 10Gi documents + 1Gi Redis)
  • Redis 8 Alpine for PHP session storage

Components

OpenEMR Container

  • Base: CentOS 10 Stream
  • PHP: 8.5 (from Remi's repository)
  • Web Server: nginx + PHP-FPM (via supervisord)
  • OpenEMR: 8.0.0
  • Session Storage: Redis (tcp://redis:6379)
  • Features:
    • OpenShift SCC compliant (runs as arbitrary UID)
    • Health check endpoints
    • OPcache enabled for performance
    • All required PHP extensions
    • Redis session handler for scalability

Redis Cache

  • Image: Redis 8 Alpine (docker.io/redis:8-alpine)
  • Storage: 1Gi RWO persistent volume (gp3)
  • Purpose: PHP session storage
  • Configuration:
    • maxmemory: 256MB with LRU eviction policy
    • Persistence: AOF (Append Only File)
    • Non-root execution (OpenShift restricted SCC)

Database

  • Image: Fedora MariaDB 11.8 (quay.io/fedora/mariadb-118)
  • Storage: 5Gi RWO persistent volume (gp3)
  • Credentials: Auto-generated secure passwords

Storage

  • Documents: 10Gi RWO volume (for patient documents, images) - gp3 EBS
  • Database: 5Gi RWO volume (for MariaDB data) - gp3 EBS
  • Redis: 1Gi RWO volume (for session persistence) - gp3 EBS
  • Storage Class: gp3 (AWS EBS CSI driver, default in Developer Sandbox)
  • Total: 16Gi

Prerequisites

  • Red Hat OpenShift Developer Sandbox account (Get free access)
  • oc CLI tool installed and configured
  • Access to Quay.io for pulling container images (or build your own)
  • Basic understanding of Kubernetes/OpenShift concepts

Developer Sandbox Limitations to be aware of:

  • Projects expire after 30 days of inactivity
  • Storage limited to ~40GB total per namespace
  • Resource quotas: Limited CPU/memory per namespace
  • No cluster-admin access
  • Single replica deployments recommended for persistent storage

Quick Start

1. Clone the Repository

git clone https://github.com/ryannix123/openemr-openshift.git
cd openemr-openshift

2. Build the Container (Optional)

If you want to build your own container:

# Build the container (creates both :latest and :8.0.0 tags)
podman build -t quay.io/ryan_nix/openemr-openshift:latest .

# Push to Quay.io
podman login quay.io
podman push quay.io/ryan_nix/openemr-openshift:latest

Or use the pre-built image: quay.io/ryan_nix/openemr-openshift:latest

3. Configure the Deployment (Optional)

The script is pre-configured for Developer Sandbox with sensible defaults:

  • Storage: gp3 (default Developer Sandbox storage class)
  • Database: 5Gi
  • Documents: 10Gi

You can optionally adjust these in deploy-openemr.sh if needed, but defaults work well for most cases.

4. Login to OpenShift Developer Sandbox

# Get your login command from the Developer Sandbox web console
oc login --token=sha256~xxxxx --server=https://api.sandbox.xxxxx.openshiftapps.com:6443

5. Deploy OpenEMR

chmod +x deploy-openemr.sh
./deploy-openemr.sh

The script will:

  1. Create the OpenShift project
  2. Deploy MariaDB with persistent storage
  3. Deploy OpenEMR application
  4. Create routes for external access
  5. Display access credentials

6. Complete OpenEMR Setup

  1. Navigate to the URL provided in the deployment summary
  2. Follow the OpenEMR setup wizard
  3. Use the database credentials from openemr-credentials.txt

Configuration

Storage Classes

The deployment uses AWS EBS gp3 storage (default in Developer Sandbox):

  • Access Mode: ReadWriteOnce (RWO) only
  • Storage Class: gp3 (default)
  • Available: gp2, gp2-csi, gp3, gp3-csi (all RWO)
  • Not Available: ReadWriteMany (RWX) storage

Note: Due to RWO storage limitations, OpenEMR runs as a single replica. This is suitable for development, testing, and small practice environments.

Scaling

Important: Scaling to multiple replicas is not supported with RWO storage. If you need high availability:

  1. Deploy on a full OpenShift cluster with RWX storage (e.g., ODF CephFS)
  2. Update storage class to RWX-capable storage
  3. Change ReadWriteOnce to ReadWriteMany in documents PVC
  4. Then scale: oc scale deployment/openemr --replicas=3 -n openemr

Resource Limits

Current resource allocations (optimized for Developer Sandbox):

OpenEMR Pod:

  • Requests: 384Mi RAM, 200m CPU
  • Limits: 768Mi RAM, 500m CPU

MariaDB:

  • Requests: 512Mi RAM, 200m CPU
  • Limits: 1Gi RAM, 500m CPU

Redis:

  • Requests: 128Mi RAM, 100m CPU
  • Limits: 256Mi RAM, 250m CPU

Total Namespace Usage:

  • RAM: ~1Gi requests, ~2Gi limits
  • CPU: ~500m requests, ~1250m limits
  • Storage: 16Gi (5Gi DB + 10Gi documents + 1Gi Redis)

These values fit within typical Developer Sandbox namespace quotas.

Container Details

PHP Configuration

The container includes these PHP settings optimized for OpenEMR:

upload_max_filesize = 128M
post_max_size = 128M
memory_limit = 512M
max_execution_time = 300

# Session storage via Redis
session.save_handler = redis
session.save_path = "tcp://redis:6379"

PHP Extensions

All required OpenEMR extensions are included:

  • php-mysqlnd (database)
  • php-gd (image processing)
  • php-xml (XML processing)
  • php-mbstring (multi-byte strings)
  • php-zip (compression)
  • php-curl (HTTP requests)
  • php-opcache (performance)
  • php-ldap (LDAP authentication)
  • php-soap (web services)
  • php-imap (email)
  • php-sodium (encryption)
  • php-pecl-redis5 (session storage)

Health Checks

The container exposes these endpoints:

  • /health - General health check (returns 200)
  • /fpm-status - PHP-FPM status page

Troubleshooting

View Logs

# OpenEMR application logs
oc logs -f deployment/openemr -n openemr

# MariaDB logs
oc logs -f statefulset/mariadb -n openemr

# Get all pods
oc get pods -n openemr

Common Issues

Pod not starting:

# Describe the pod for events
oc describe pod <pod-name> -n openemr

# Check for image pull errors
oc get events -n openemr --sort-by='.lastTimestamp'

Storage issues:

# Check PVC status
oc get pvc -n openemr

# Describe PVC for binding issues
oc describe pvc <pvc-name> -n openemr

Database connection errors:

# Verify MariaDB is running
oc get pods -l app=mariadb -n openemr

# Test database connectivity from OpenEMR pod
oc exec -it deployment/openemr -n openemr -- bash
# Inside the pod:
php -r "mysqli_connect('mariadb', 'openemr', 'password', 'openemr') or die(mysqli_connect_error());"

Reset Deployment

To completely remove and redeploy:

oc delete project openemr
# Wait for project to fully delete, then re-run:
./deploy-openemr.sh

Security Considerations

HIPAA Compliance

This deployment includes several security features for healthcare environments:

  1. Encryption in Transit: TLS/HTTPS via OpenShift routes
  2. Encryption at Rest: Enable encrypted storage classes
  3. Access Controls: Leverage OpenShift RBAC
  4. Audit Logging: OpenEMR's built-in audit log
  5. Network Policies: Implement NetworkPolicy objects

Recommended Enhancements

For production healthcare deployments:

  1. Enable Encryption at Rest:

    # Use encrypted storage classes
    STORAGE_CLASS="ocs-storagecluster-ceph-rbd-encrypted"
  2. Implement Network Policies:

    # Deny all traffic except necessary connections
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: openemr-netpol
    spec:
      podSelector:
        matchLabels:
          app: openemr
      policyTypes:
      - Ingress
      - Egress
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              name: openshift-ingress
      egress:
      - to:
        - podSelector:
            matchLabels:
              app: mariadb
        ports:
        - protocol: TCP
          port: 3306
  3. Configure Backup Strategy:

    # Use OADP or Velero for backup/restore
    # Schedule regular database backups
  4. Enable Pod Security Standards:

    oc label namespace openemr \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/warn=restricted

Service Mesh — Zero Trust Networking

The service-mesh/ sub-project adds a zero-trust networking layer using OpenShift Service Mesh 3 (OSSM 3) in ambient mode. This is an optional but strongly recommended addition for any environment handling real patient data.

Why Service Mesh for a Healthcare Workload?

The base deployment secures the perimeter — TLS on the route, resource isolation via namespaces — but by default, pod-to-pod traffic inside the cluster is unencrypted and unrestricted. Any workload that gains a foothold in the openemr namespace can freely connect to MariaDB or Redis and sniff credentials or patient data in transit. The service mesh closes this gap.

What OSSM 3 Ambient Mode Adds

Layer What It Does
Automatic mTLS (ztunnel) All pod-to-pod traffic is encrypted and mutually authenticated without any changes to OpenEMR, MariaDB, or Redis
Identity-based AuthorizationPolicies Only OpenEMR's service account identity can reach MariaDB (port 3306) and Redis (port 6379) — no other pod can connect regardless of IP
Waypoint Proxy Enforces L7 policies via an Envoy-based proxy deployed per namespace, required for fine-grained HTTP-level controls
NetworkPolicies L3/L4 isolation enforced by OVN-Kubernetes independent of the mesh — defense in depth
EgressFirewall Pods may only initiate outbound connections to an explicit allow-list; a compromised pod cannot phone home

Ambient Mode vs. Traditional Sidecar (OSSM 2.x)

OSSM 3 uses a fundamentally different architecture. Instead of injecting an Envoy sidecar into every pod (which requires pod restarts and shows as 2/2 containers), ambient mode deploys a ztunnel DaemonSet that intercepts traffic at the Linux network namespace level on each node. Pods remain 1/1 and are enrolled simply by labeling the namespace — no rollout required. A separate waypoint proxy handles L7 policy enforcement only where needed.

Requirement: OSSM 3 requires cluster-admin access to install the Sail Operator and the IstioCNI DaemonSet. It is not compatible with the Developer Sandbox. Use a full OpenShift cluster or Single Node OpenShift (SNO).

Quick Start

cd service-mesh/
chmod +x deploy-mesh.sh

# Full install: operators, control plane, policies, Kiali
./deploy-mesh.sh --full

# Or step by step — useful if OpenEMR is already deployed:
./deploy-mesh.sh --operators      # Install Sail + Kiali operators, Gateway API CRDs
./deploy-mesh.sh --control-plane  # Deploy Istio + ztunnel
./deploy-mesh.sh --policies       # Enroll namespace, waypoint, AuthZ, NetworkPolicy, Egress

# Check status at any point
./deploy-mesh.sh --status

See service-mesh/README.md for the full deployment guide, manifest reference, HIPAA alignment table, and troubleshooting steps.

Project Structure

openemr-on-openshift/
├── Containerfile                  # Container build instructions
├── deploy-openemr.sh              # Automated deployment script
├── README.md                      # This file
├── .containerignore               # Files to ignore during build
├── manifests/                     # Individual YAML manifests
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── route.yaml
│   └── mariadb/
│       ├── statefulset.yaml
│       └── service.yaml
└── service-mesh/                  # Zero-trust networking sub-project (OSSM 3)
    ├── README.md                  # Service mesh deployment guide
    ├── deploy-mesh.sh             # Operator + mesh deployment script
    └── manifests/
        ├── 00-sail-operator.yaml  # Sail Operator subscription (OLM)
        ├── 00-kiali-operator.yaml # Kiali Operator subscription + Kiali CR
        ├── 01-istio.yaml          # Istio CR (ambient profile)
        ├── 02-istiocni.yaml       # IstioCNI CR (ztunnel DaemonSet)
        ├── 03-namespace.yaml      # Namespace with ambient enrollment label
        ├── 04-waypoint.yaml       # Waypoint proxy (L7 policy enforcement)
        ├── 05-authz-policies.yaml # AuthorizationPolicies (default-deny + allows)
        ├── 06-network-policies.yaml # NetworkPolicies (L3/L4 CNI isolation)
        └── 07-egress-firewall.yaml  # EgressFirewall (OVN-Kubernetes)

Contributing

Contributions are welcome! Areas for improvement:

  • Helm chart version
  • GitOps/ArgoCD manifests
  • Automated database migrations
  • Prometheus metrics exporters
  • Custom Operator
  • Multi-tenancy support

Resources

License

This project follows OpenEMR's licensing. OpenEMR is licensed under GPL v3.

Author

Ryan Nix

Acknowledgments

  • OpenEMR development team
  • Red Hat OpenShift team
  • Based on the Nextcloud on OpenShift pattern

Note: This is designed for healthcare environments. Ensure compliance with HIPAA, HITECH, and other applicable regulations in your jurisdiction before deploying with real patient data.

About

OpenEMR on OpenShift

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Shell 62.9%
  • Dockerfile 37.1%