Skip to content

Jmevorach/openemr-static-binary-forge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenEMR Static Binary Forge Logo

This project provides tools to build self-contained, statically compiled OpenEMR binaries for multiple platforms. Three out of four builds (macOS, Linux amd64, and Linux arm64) use Static PHP CLI (SPC), while the FreeBSD build uses a custom method to compile a static distribution. The resulting binaries include OpenEMR and PHP runtime with all dependencies in a single executable that can run without additional dependencies (note: OpenEMR needs an external MySQL database to function whether it's run in a static binary or not).

Table of Contents

Currently Supported Platforms

This project supports building OpenEMR static binaries for four platforms:

Note: All platforms have been verified with OpenEMR v7.0.4 and PHP 8.5.

Each platform has its own build directory with platform-specific build scripts and documentation.

What is OpenEMR?

OpenEMR is a popular open-source electronic health records (EHR) and medical practice management application. This project allows you to create a portable, standalone binary version.

Features

  • Self-contained static binary: Everything needed to run OpenEMR is included in a single executable
  • Fully static / Bundled Libs: All dependencies are statically linked or bundled (FreeBSD)
  • No dependencies: No need to install PHP or other software on target systems
  • Portable: Copy the binary to any compatible system and run it
  • Optimized builds: Automatically uses all available CPU cores and RAM for faster builds
  • Automated Web Server Runners: Includes scripts for both PHP's built-in server and Apache HTTP Server (with both CGI and FPM support)
  • Easy to use: Single executable with OpenEMR and PHP runtime

Platform Build Guides

macOS

See the macOS Build Guide for complete instructions on building OpenEMR static binaries for macOS (Apple Silicon and Intel).

Linux (arm64)

See the Linux arm64 Build Guide for complete instructions on building OpenEMR static binaries for Linux arm64 using Docker.

Linux (amd64)

See the Linux amd64 Build Guide for complete instructions on building OpenEMR static binaries for Linux amd64 using Docker.

FreeBSD

See the FreeBSD Build Guide for complete instructions on building OpenEMR binaries for FreeBSD using QEMU on macOS.

Key features:

  • Builds native FreeBSD binaries from macOS using QEMU virtualization
  • PHP compiled from source with all required extensions
  • Bundled shared libraries for portability
  • VM runner script for testing on macOS (built-in server)
  • VM Apache runner for realistic testing on macOS
  • Works on actual FreeBSD systems with bundled libs

Project Structure

openemr-static-binary-forge/
├── README.md                          # This file (main documentation)
├── LICENSE                            # Project license
├── mac_os/                            # macOS build files
│   ├── build-macos.sh                 # macOS build script
│   ├── run-web-server.sh              # macOS web server launcher
│   ├── php.ini                        # PHP configuration (customizable)
│   ├── apache_cgi/                    # Apache HTTP Server integration (CGI)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-wrapper.sh             # PHP CGI wrapper script template
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-cgi-setup.sh          # CGI setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   └── README.md                  # Apache CGI setup instructions
│   ├── apache_fpm/                    # Apache HTTP Server integration (FPM)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-fpm.conf               # PHP-FPM configuration
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-fpm-setup.sh          # FPM setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-fpm.sh                 # PHP-FPM launcher script
│   │   └── README.md                  # Apache FPM setup instructions
│   └── README.md                      # macOS build guide
├── linux_amd64/                       # Linux amd64 build files
│   ├── build-linux.sh                 # Linux amd64 build script
│   ├── run-web-server.sh              # Linux amd64 web server launcher (Docker)
│   ├── run-fpm.sh                     # PHP-FPM launcher script
│   ├── Dockerfile                     # Docker image for running OpenEMR
│   ├── docker-compose.yml             # Docker Compose configuration
│   ├── docker-entrypoint.sh           # Container entrypoint script
│   ├── docker-entrypoint-wrapper.sh   # Permissions wrapper
│   ├── php.ini                        # PHP configuration (customizable)
│   ├── apache_cgi/                    # Apache HTTP Server integration (CGI)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-wrapper.sh             # PHP CGI wrapper script template
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-cgi-setup.sh          # CGI setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-apache-docker.sh       # Docker-based Apache launcher
│   │   ├── Dockerfile.docker          # Docker image for Apache setup
│   │   └── README.md                  # Apache CGI setup instructions
│   ├── apache_fpm/                    # Apache HTTP Server integration (FPM)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-fpm.conf               # PHP-FPM configuration
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-fpm-setup.sh          # FPM setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-fpm-docker.sh          # Docker-based FPM launcher
│   │   ├── run-fpm.sh                 # PHP-FPM launcher script
│   │   ├── Dockerfile.docker          # Docker image for FPM setup
│   │   └── README.md                  # Apache FPM setup instructions
│   └── README.md                      # Linux amd64 build guide
├── linux_arm64/                       # Linux arm64 build files
│   ├── build-linux.sh                 # Linux arm64 build script
│   ├── run-web-server.sh              # Linux arm64 web server launcher (Docker)
│   ├── run-fpm.sh                     # PHP-FPM launcher script
│   ├── Dockerfile                     # Docker image for running OpenEMR
│   ├── docker-compose.yml             # Docker Compose configuration
│   ├── docker-entrypoint.sh           # Container entrypoint script
│   ├── docker-entrypoint-wrapper.sh   # Permissions wrapper
│   ├── php.ini                        # PHP configuration (customizable)
│   ├── apache_cgi/                    # Apache HTTP Server integration (CGI)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-wrapper.sh             # PHP CGI wrapper script template
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-cgi-setup.sh          # CGI setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-apache-docker.sh       # Docker-based Apache launcher
│   │   ├── Dockerfile.docker          # Docker image for Apache setup
│   │   └── README.md                  # Apache CGI setup instructions
│   ├── apache_fpm/                    # Apache HTTP Server integration (FPM)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-fpm.conf               # PHP-FPM configuration
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-fpm-setup.sh          # FPM setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-fpm-docker.sh          # Docker-based FPM launcher
│   │   ├── run-fpm.sh                 # PHP-FPM launcher script
│   │   ├── Dockerfile.docker          # Docker image for FPM setup
│   │   └── README.md                  # Apache FPM setup instructions
│   └── README.md                      # Linux arm64 build guide
├── freebsd/                           # FreeBSD build files
│   ├── build-freebsd.sh               # FreeBSD build script (uses QEMU)
│   ├── run-freebsd-vm.sh              # Run OpenEMR in FreeBSD VM (built-in server)
│   ├── run-freebsd-apache.sh          # Run OpenEMR with Apache in FreeBSD VM (CGI)
│   ├── run-freebsd-fpm.sh             # Run OpenEMR with Apache + FPM in FreeBSD VM
│   ├── run-web-server.sh              # Web server for native FreeBSD
│   ├── router.php                     # Router script for PHP built-in server
│   ├── php.ini                        # PHP configuration (customizable)
│   ├── verify-apache-setup.sh         # Apache setup verification script
│   ├── apache_cgi/                    # Apache HTTP Server integration (CGI)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-wrapper.sh             # PHP CGI wrapper script template
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-cgi-setup.sh          # CGI setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   └── README.md                  # Apache CGI setup instructions
│   ├── apache_fpm/                    # Apache HTTP Server integration (FPM)
│   │   ├── httpd-openemr.conf         # Apache virtual host configuration
│   │   ├── php-fpm.conf               # PHP-FPM configuration
│   │   ├── setup-apache-config.sh     # Automated Apache configuration script
│   │   ├── test-fpm-setup.sh          # FPM setup verification script
│   │   ├── benchmark.sh               # Apache performance benchmarking script
│   │   ├── extract-openemr.sh         # OpenEMR extraction script
│   │   ├── run-fpm.sh                 # PHP-FPM launcher script
│   │   └── README.md                  # Apache FPM setup instructions
│   └── README.md                      # FreeBSD build guide
├── images/                            # Screenshots and visual assets
│   └── [various screenshot files]
└── logo/                              # Project logos
    └── [various logo files]

How It Works

The build process follows these steps (with platform-specific variations):

  1. System Detection: Automatically detects CPU cores and RAM to optimize build performance

    • Detects physical and logical CPU cores
    • Calculates optimal parallel build jobs
    • Sets appropriate memory limits for Composer and npm
  2. Prepare OpenEMR: Clones the specified OpenEMR version and prepares it for packaging

    • Removes unnecessary files
    • Installs production dependencies via Composer (using parallel processes)
    • Builds frontend assets (with optimized memory allocation)
    • Creates a PHAR archive containing the application
  3. Setup Static PHP CLI (SPC):

    • macOS: Downloads pre-built SPC binary for the target architecture
    • Linux: Builds SPC from source inside Docker container
    • FreeBSD: Builds PHP directly from source (SPC not available for FreeBSD)
  4. Build Static PHP: Uses SPC to build static PHP binaries:

    • macOS: Builds directly on the host system
    • Linux: Builds inside Docker container (ensures consistent build environment)
    • FreeBSD: Builds PHP from source inside QEMU VM, bundles shared libraries
    • Downloads PHP and extension sources (or builds PHP from source for Linux/FreeBSD)
    • Compiles PHP CLI and MicroSFX with all required extensions
    • All dependencies are statically linked (or bundled as shared libs for FreeBSD)
  5. Combine Binary: Combines the PHAR archive with the MicroSFX binary to create a single executable:

    • OpenEMR application code (in PHAR format)
    • PHP runtime with all extensions
    • Single self-contained binary
  6. Output: The final static binary, PHP CLI binary, and PHAR archive are saved:

    • macOS: Saved in the mac_os/ directory
    • Linux: Saved in the respective linux_amd64/ or linux_arm64/ directory
    • FreeBSD: Saved in freebsd/dist/ directory (includes lib/ with bundled shared libraries)
    • All platforms: Also copied to the project root for easier access

Static Binary Details

The resulting binary:

  • Contains both the PHP interpreter and the OpenEMR application
  • Self-extracts and executes when run to serve static files (CSS, images, etc.)
  • macOS: Can run on any macOS system of the same architecture (Apple Silicon or Intel)
  • Linux: Can run on any Linux system of the same architecture (amd64 or arm64)
  • FreeBSD: Can run on FreeBSD systems with bundled shared libraries (lib/ directory required)
  • Fully portable and self-contained

This method is based on the approach described in Creating Standalone PHP App Binaries using Static PHP CLI.

Performance Optimization

The build scripts automatically optimize for your system:

Automatic Resource Detection

All platforms automatically detect and optimize:

  • CPU Cores: Detects physical and logical CPU cores
  • RAM: Detects total system RAM (or Docker container RAM for Linux)
  • Parallel Jobs: Calculates optimal parallel build jobs (typically physical cores + 1)
  • Memory Limits: Sets appropriate memory limits for Composer and npm based on available RAM

Build Optimizations

  • Parallel Compilation: Uses all available CPU cores for faster builds
  • Composer: Uses parallel processes for dependency installation
  • npm: Optimized memory allocation based on system RAM
  • Static Linking: Creates fully static binary where possible
  • Debug Symbols: Stripped to reduce binary size
  • Docker Memory Allocation (Linux): Allocates 16GB RAM to Docker containers for optimal build performance

Customizing Build Performance

You can manually override the automatic detection by setting environment variables before running the script:

# Force specific number of parallel jobs (macOS only)
export PARALLEL_JOBS=8

# Override Composer memory limit
export COMPOSER_MEMORY_LIMIT=4G

# Specify PHP version (Linux builds)
export PHP_VERSION=8.4

# Run the build (platform-specific)
cd mac_os && ./build-macos.sh          # macOS
cd linux_amd64 && ./build-linux.sh     # Linux amd64
cd linux_arm64 && ./build-linux.sh     # Linux arm64
cd freebsd && ./build-freebsd.sh       # FreeBSD (via QEMU)

Troubleshooting

Platform-Specific Issues

Each platform has its own troubleshooting guide:

Common Issues

Build Fails with Missing Libraries (macOS)

If you get errors about missing libraries during the build on macOS:

# Install all required development libraries
brew install \
  libpng \
  libjpeg \
  freetype \
  libxml2 \
  libzip \
  imagemagick \
  pkg-config

Important: pkg-config is required for the build process to detect system libraries.

Docker Not Running (Linux)

If you get errors about Docker not being available on Linux:

# Check if Docker is running
docker info

# Start Docker Desktop (macOS/Windows)
# Or start Docker daemon (Linux)
sudo systemctl start docker

QEMU Not Installed (FreeBSD Build)

If you get errors about QEMU not being available when building for FreeBSD:

# Install QEMU and expect on macOS
brew install qemu expect

Out of Memory During Build

If you run out of memory during the build:

  • Close other applications to free up RAM
  • macOS: Reduce parallel build jobs by setting PARALLEL_JOBS environment variable
  • Linux: Ensure Docker has enough memory allocated (default: 16GB)
  • Consider building on a machine with more RAM

Composer Dependencies Fail

If Composer dependency installation fails:

  • Ensure you have a stable internet connection
  • Try increasing PHP memory limit: COMPOSER_MEMORY_LIMIT=2G composer install
  • Check if the OpenEMR version you're trying to build exists and is valid

Frontend Build Fails

If npm builds fail:

  • macOS: Ensure Node.js is installed: brew install node
  • Linux: Node.js is included in the Docker build image
  • Try clearing npm cache: npm cache clean --force
  • Check if the OpenEMR version supports the Node.js version you have installed

SPC Download/Build Fails

  • macOS: Check your internet connection and try again later
  • Linux: SPC is built from source, ensure Docker has enough resources
  • FreeBSD: Does not use SPC; PHP is built directly from source
  • Check the Static PHP CLI releases page for more information

PHP Extensions Included

The build includes these PHP extensions required by OpenEMR:

Core Extensions (macOS, Linux amd64, Linux arm64)

  • bcmath - Arbitrary precision mathematics
  • calendar - Calendar conversion functions
  • ctype - Character type checking
  • curl - Client URL library
  • dom - DOM manipulation
  • exif - Exchangeable image information
  • fileinfo - File information detection
  • filter - Data filtering
  • gd - GD graphics library (with JPEG and PNG support)
  • imagick - ImageMagick image processing
  • intl - Internationalization functions
  • ldap - Lightweight Directory Access Protocol
  • mbstring - Multibyte string handling
  • mysqli - MySQL improved extension
  • opcache - OPcode cache
  • openssl - OpenSSL cryptography
  • pcntl - Process control
  • pdo_mysql - MySQL PDO driver
  • phar - PHP Archive
  • redis - Redis client
  • simplexml - Simple XML parsing
  • soap - SOAP client/server
  • sockets - Low-level socket functions
  • tokenizer - PHP tokenizer
  • xmlreader - XML reader
  • xmlwriter - XML writer
  • xsl - XSLT processing
  • zip - ZIP archive handling

Additional Extensions (FreeBSD)

FreeBSD builds include additional extensions beyond the core set:

  • ftp - FTP client
  • gettext - Gettext internationalization
  • hash - Hash functions
  • iconv - Character encoding conversion
  • json - JSON support
  • libxml - LibXML support
  • mysqlnd - MySQL native driver
  • pdo - PHP Data Objects
  • pdo_sqlite - SQLite PDO driver
  • posix - POSIX functions
  • session - Session handling
  • sodium - Sodium cryptography
  • sqlite3 - SQLite3 database
  • xml - XML parsing
  • zlib - Zlib compression

Note: The build uses PHP (version specified by PHP_VERSION environment variable, default: 8.5) with all required extensions statically compiled. Linux builds compile PHP from source, while macOS builds use pre-built PHP sources. FreeBSD builds compile PHP from source and include a more comprehensive set of extensions.

Usage

After building, you'll have a single binary file that includes PHP and OpenEMR. To use it:

  1. macOS: Run the binary directly or use the included run-web-server.sh script
  2. Linux: Use Docker Compose with the included run-web-server.sh script (recommended) or run the binary directly
  3. FreeBSD (on macOS): Use run-freebsd-vm.sh to boot a QEMU VM and run OpenEMR
  4. FreeBSD (native): Copy the distribution to FreeBSD and use run-web-server.sh or run directly
  5. For web applications, you can use PHP's built-in server (included in launcher scripts) or set up a production web server (Apache, Nginx, etc.)
  6. The binary is portable - copy it to any compatible system of the same architecture and run it

Running the Web Server

Each platform includes a web server launcher script:

Platform Command Notes
macOS cd mac_os && ./run-web-server.sh [port] Uses built-in PHP server
macOS (Apache CGI) cd mac_os/apache_cgi && ./setup-apache-config.sh Configures local Apache with CGI
macOS (Apache FPM) cd mac_os/apache_fpm && ./setup-apache-config.sh Configures local Apache with FPM
Linux (amd64) cd linux_amd64 && ./run-web-server.sh [port] Uses Docker Compose
Linux (amd64 FPM) cd linux_amd64 && ./run-fpm.sh Runs FPM binary
Linux (amd64 Apache CGI) cd linux_amd64/apache_cgi && ./run-apache-docker.sh Docker-based Apache with CGI
Linux (amd64 Apache FPM) cd linux_amd64/apache_fpm && ./run-fpm-docker.sh Docker-based Apache with FPM
Linux (arm64) cd linux_arm64 && ./run-web-server.sh [port] Uses Docker Compose
Linux (arm64 FPM) cd linux_arm64 && ./run-fpm.sh Runs FPM binary
Linux (arm64 Apache CGI) cd linux_arm64/apache_cgi && ./run-apache-docker.sh Docker-based Apache with CGI
Linux (arm64 Apache FPM) cd linux_arm64/apache_fpm && ./run-fpm-docker.sh Docker-based Apache with FPM
FreeBSD (VM) cd freebsd && ./run-freebsd-vm.sh -p [port] Uses QEMU + built-in server
FreeBSD (Apache VM CGI) cd freebsd && ./run-freebsd-apache.sh -p [port] Uses QEMU + Apache (CGI)
FreeBSD (FPM VM) cd freebsd && ./run-freebsd-fpm.sh -p [port] Uses QEMU + Apache (FPM)
FreeBSD (Native) cd freebsd && ./run-web-server.sh [port] Uses built-in PHP server

The launcher scripts handle PHAR extraction and start PHP's built-in development server. For production use, configure a proper web server according to OpenEMR's documentation.

PHP Configuration (php.ini)

A customizable php.ini file is included in each platform's build directory that configures PHP settings for OpenEMR. The web server launcher automatically uses this file if it's present.

Location

The php.ini file is located in each platform's directory:

mac_os/php.ini
linux_amd64/php.ini
linux_arm64/php.ini
freebsd/php.ini

Automatic Usage

The php.ini file is automatically used by:

  • macOS: The web server launcher (run-web-server.sh) for PHAR extraction and PHP's built-in web server
  • Linux: The Docker container entrypoint script when serving OpenEMR via Docker Compose
  • FreeBSD: The VM runner (run-freebsd-vm.sh) and native web server script

If the file is not found, PHP will use its default settings. You can customize the php.ini file in your platform's directory to adjust memory limits, timeouts, and other PHP settings.

Router Script (router.php)

Important: The router script and PHP's built-in server are intended for development and testing purposes only. For production deployments, you should use a proper web server such as Apache as recommended in OpenEMR's documentation.

The router script is an illustrative tool that demonstrates how to properly serve OpenEMR with PHP's built-in development server. It ensures that static files (CSS, JavaScript, images) are served correctly and routes requests to the appropriate OpenEMR entry points. This script helps developers understand the routing requirements and test OpenEMR builds locally, but should not be used in production environments.

Purpose

PHP's built-in server requires a router script to:

  • Serve static files directly: CSS, JavaScript, images, and other assets are served without PHP processing
  • Route to OpenEMR entry points: Requests are properly routed to OpenEMR's interface entry points
  • Set correct server variables: Configures SCRIPT_NAME, PHP_SELF, and DOCUMENT_ROOT for OpenEMR

Without the router script, you may experience:

  • Missing CSS styling
  • Non-functional JavaScript
  • Broken image loading
  • Incorrect routing of requests

Location and Usage

The router script is used automatically by all web server launchers:

  • macOS: Created dynamically by run-web-server.sh in a temporary directory
  • Linux (Docker): Created dynamically by docker-entrypoint.sh in /tmp/router.php
  • FreeBSD (VM): Downloaded from freebsd/router.php or created as a fallback in the VM

FreeBSD Static Router File

For FreeBSD builds, a static router.php file is included in the freebsd/ directory. This file is:

  • Automatically copied to the shared directory for VM testing
  • Used by the FreeBSD VM runner script (run-freebsd-vm.sh)
  • Can be customized if needed for specific routing requirements

The router script location:

freebsd/router.php

How It Works

The router script:

  1. Checks for static files: If the requested file exists and is not a directory, it returns false, allowing PHP's built-in server to serve it directly
  2. Searches for OpenEMR entry points: Looks for common OpenEMR entry points in order:
    • /interface/main/main.php (standard OpenEMR structure)
    • /interface/main.php
    • /main.php
    • /index.php
  3. Sets server variables: Configures PHP superglobals to match OpenEMR's expectations
  4. Includes the entry point: Requires the found entry point to serve the request

Customization

While the router script works out of the box, you can customize it for specific needs:

  • Modify the freebsd/router.php file for FreeBSD builds
  • Edit the router creation logic in the web server launcher scripts for other platforms
  • Add custom routing logic for specific URL patterns

Important: Changes to the router script may affect OpenEMR's functionality. Test thoroughly after making modifications.

Production Deployment

The router script and PHP's built-in server should NOT be used in production. PHP's built-in web server is explicitly designed for development and testing only. It lacks essential production features such as:

  • Performance optimization and caching
  • Security hardening
  • Process management and supervision
  • Load balancing and high availability
  • Advanced logging and monitoring
  • HTTPS/SSL termination
  • Rate limiting and DDoS protection

License

See the LICENSE file for license information. Uses the MIT license.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

References

Support

For issues specific to this build system, please open an issue in this repository.

For OpenEMR-specific issues, please refer to the OpenEMR project.

About

Tools to build self-contained OpenEMR static binaries.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages