Skip to main content

OpenEMR CloudRun Module — Configuration Guide

OpenEMR CloudRun deploys OpenEMR Community Edition — an open-source Electronic Health Records (EHR) and medical practice management platform — on Google Cloud Run Gen 2. The application runs on Apache with PHP 8.3 FPM on Alpine 3.20, backed by Cloud SQL MySQL 8.0 connected via Unix socket, and a Cloud Filestore NFS volume that persists the sites directory containing patient documents and application state.

OpenEMR CloudRun is a wrapper module built on top of App CloudRun. All GCP infrastructure is provisioned by App CloudRun. The module adds OpenEMR-specific configuration, a platform-managed nfs-init job for storage preparation and backup restoration, auto-generated admin password and database password secrets, and runtime defaults tuned for healthcare availability requirements.

The module uses OpenEMR Common as a sub-module to resolve application configuration, scripts, and storage bucket lists, which are passed into App CloudRun via application_config, module_env_vars, module_secret_env_vars, and module_storage_buckets.


§1 · Module Overview

AttributeValue
Underlying platformApp CloudRun
Sub-moduleOpenEMR Common
ApplicationOpenEMR (Apache/PHP 8.3 FPM on Alpine 3.20)
Default version7.0.4
DatabaseCloud SQL MySQL 8.0 (required; Unix socket connection)
Persistent storageCloud Filestore NFS (enable_nfs = true by default)
NFS mount path/var/www/localhost/htdocs/openemr/sites
Default container port80
Min instances default1 (healthcare availability; scale-to-zero not recommended)
Max instances default1 (increase only after configuring Redis)
RedisEnabled by default (enable_redis = true); uses NFS server IP when no host is set
Platform-managed jobnfs-init (NFS setup + optional backup restoration)
Platform-managed secretsOE_PASS (admin password) + MYSQL_PASS (database password)

Wrapper Architecture

OpenEMR_CloudRun (variables.tf / openemr.tf / main.tf)
└─ OpenEMR_Common ← resolves app config, nfs-init job, admin-pass secret
└─ App_CloudRun ← provisions all GCP infrastructure

OpenEMR Common outputs:

  • config → merged into application_config (with BACKUP_FILEID injected into nfs-init when backup_uri is set)
  • admin_password_secret_id → injected as OE_PASS via module_secret_env_vars
  • storage_buckets → merged into module_storage_buckets
  • path → used to resolve scripts_dir

The MYSQL_PASS secret is sourced directly from module.app_cloudrun.database_password_secret and injected alongside OE_PASS via module_secret_env_vars.


§2 · IAM & Project Identity

VariableDefaultDescription
project_idGCP project ID. All resources are created in this project. Grant the Owner role to rad-module-creator@tec-rad-ui-2b65.iam.gserviceaccount.com.
tenant_deployment_id"demo"Short suffix appended to resource names. Use "prod", "clinic-1", etc. to deploy multiple environments in the same project.
resource_creator_identity"rad-module-creator@…"Service account used by Terraform. Override with a project-specific SA for production.
support_users[]Email addresses of users granted IAM access and added as monitoring alert recipients.
resource_labels{}Key-value labels applied to all resources (cost centre, team, environment).
deployment_id""Optional fixed deployment ID. A random hex ID is generated when left empty.

§3 · Core Service Configuration

§3.A · Application Identity

display_name and description are OpenEMR-specific aliases for application_display_name and application_description, passed directly to OpenEMR Common and then to App CloudRun.

VariableDefaultDescription
application_name"openemr"Internal identifier used as the base name for the Cloud Run service, Artifact Registry repository, Secret Manager secrets, and GCS buckets. Do not change after initial deployment.
display_name"OpenEMR"Human-readable name shown in the platform UI, Cloud Run console, and monitoring dashboards. Safe to update at any time.
description"OpenEMR Electronic Health Records on Cloud Run"Brief description. Populates the Cloud Run service description field and platform documentation.
application_version"7.0.4"OpenEMR release version used as the container image tag. Changing this triggers a new image build. Supported values: "7.0.4", "7.0.3".

§3.B · Resource Sizing

OpenEMR's PHP-FPM workers and database connection pool consume 1.5–3 Gi under normal clinical load. cpu_limit and memory_limit are built directly into container_resources passed to App CloudRun.

VariableDefaultDescription
cpu_limit"2000m"CPU per instance. "2000m" is the recommended minimum for production with concurrent clinical users. CPU above "1000m" requires min_instance_count >= 1.
memory_limit"4Gi"Memory per instance. Minimum "2Gi" for production; below "2Gi" causes OOM kills during peak clinical activity.
min_instance_count1Default is 1 (not 0). Scale-to-zero is not recommended for healthcare — clinicians require immediate access without cold-start delays.
max_instance_count1Keep at 1 until Redis session store is operational; multiple instances without Redis cause PHP session loss.
timeout_seconds300Maximum request duration (0–3600 s). Increase for long-running operations (report generation, large file uploads, patient data exports).
execution_environment"gen2"Must remain "gen2" for NFS volume support. "gen1" will prevent NFS mounts and OpenEMR will fail to start.

§3.C · Environment Variables & Secrets

VariableDefaultDescription
environment_variables{}Plain-text environment variables injected at runtime. Use for PHP configuration (PHP_MEMORY_LIMIT), SMTP settings, and other non-sensitive config.
secret_environment_variables{}Map of env var name → Secret Manager secret name. Values resolved at runtime; never stored in plaintext.
secret_rotation_period"2592000s"Rotation reminder interval (30 days default). Set null to disable.
secret_propagation_delay30Seconds to wait after secret creation before dependent operations proceed.

Configuring PHP and SMTP:

environment_variables = {
PHP_MEMORY_LIMIT = "512M" # increase for large patient datasets
SMTP_HOST = "smtp.sendgrid.net"
SMTP_PORT = "587"
SMTP_USER = "apikey"
SMTP_SSL = "true"
EMAIL_FROM = "noreply@yourclinic.example.com"
}

secret_environment_variables = {
SMTP_PASSWORD = "openemr-smtp-password" # Secret Manager secret name
}

§3.D · Networking

VariableDefaultDescription
ingress_settings"all"Traffic sources permitted to reach Cloud Run. For HIPAA-aligned deployments, consider "internal-and-cloud-load-balancing" combined with Cloud Armor WAF.
vpc_egress_setting"PRIVATE_RANGES_ONLY"Routes RFC 1918 traffic (Cloud SQL, NFS, Redis) via VPC. Change to "ALL_TRAFFIC" if all egress must pass through a centralised network appliance.
container_port80Apache's listening port inside the container. Do not change unless the Apache config is modified.
container_protocol"http1"HTTP version: "http1" or "h2c". Use "http1" for OpenEMR.
cloudsql_volume_mount_path"/cloudsql"Path where the Cloud SQL Auth Proxy Unix socket is mounted. OpenEMR's sqlconf.php uses this socket path.

§3.E · Container Image & Build

OpenEMR CloudRun does not expose container_image_source or container_build_config as user variables. Image building is managed entirely by OpenEMR Common based on application_version. Set enable_image_mirroring = false only if the image is already available in a private registry.

VariableDefaultDescription
application_version"7.0.4"OpenEMR version used as the container image tag. Changing this triggers a new Cloud Build image build.
enable_image_mirroringtrueMirrors the image into Artifact Registry before deploy. Recommended to avoid Docker Hub rate limits.
deploy_applicationtrueSet false to provision infrastructure only (secrets, storage, IAM) without deploying the container.

§4 · Advanced Security

§4.A · Automated Password Rotation

VariableDefaultDescription
enable_auto_password_rotationfalseDeploys a Cloud Run + Eventarc automated rotation job. Rotates the MySQL database password on the schedule set by secret_rotation_period.
rotation_propagation_delay_sec90Seconds to wait after rotation before Cloud Run restarts to pick up the new password.
secret_rotation_period"2592000s"Rotation reminder interval. Also used as the trigger period when enable_auto_password_rotation = true.

§4.B · VPC Service Controls

VariableDefaultDescription
enable_vpc_scfalseEnforces VPC-SC perimeter. Restricts GCP API calls to requests from inside the perimeter. Requires an existing VPC-SC perimeter in the project.
vpc_cidr_ranges[]VPC subnet CIDR ranges for the VPC-SC network access level. Auto-discovered when empty.
vpc_sc_dry_runtrueWhen true, VPC-SC violations are logged but not blocked. Set to false to actively enforce the perimeter.
organization_id""GCP Organization ID for the VPC-SC Access Context Manager policy. Auto-discovered when empty.
enable_audit_loggingfalseEnables detailed Cloud Audit Logs (DATA_READ, DATA_WRITE, ADMIN_READ) for compliance-sensitive environments.

§4.C · Identity-Aware Proxy

IAP is particularly valuable for EHR applications — it restricts access to authenticated clinical staff before any request reaches OpenEMR.

VariableDefaultDescription
enable_iapfalseEnables Cloud Run native IAP. Requires Google identity authentication before the application is accessible.
iap_authorized_users[]Users granted access: "user:doctor@clinic.com", "serviceAccount:sa@project.iam.gserviceaccount.com".
iap_authorized_groups[]Google Groups granted access: "group:clinical-staff@clinic.com". Preferred for clinic-level access management.

§4.D · Cloud Armor & CDN

VariableDefaultDescription
enable_cloud_armorfalseProvisions a Global HTTPS Load Balancer with Cloud Armor WAF (OWASP Top 10, DDoS). Required when application_domains is set.
application_domains[]Custom domains. Google-managed SSL certificates are provisioned per domain. DNS must point to the GLB IP before cert provisioning completes.
enable_cdnfalseEnables Cloud CDN on the GLB to cache static assets at edge. Only used when enable_cloud_armor = true.
admin_ip_ranges[]IP CIDR ranges permitted for direct administrative access.

§4.E · Binary Authorization

VariableDefaultDescription
enable_binary_authorizationfalseEnforces Binary Authorization policy. Images must carry a valid attestation before deployment. Requires a Binary Authorization policy and attestor to be configured in the project.

§5 · Traffic & Ingress

§5.A · Traffic Splitting

VariableDefaultDescription
traffic_split[]Canary or blue-green traffic allocations across Cloud Run revisions. All entries must sum to 100%. Leave empty to route all traffic to the latest revision.

Example — canary deployment:

traffic_split = [
{ type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST", percent = 90 },
{ type = "TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION", percent = 10, revision = "openemr-00003-abc" },
]

§5.B · Service Annotations & Labels

VariableDefaultDescription
service_annotations{}Kubernetes-style annotations on the Cloud Run service resource.
service_labels{}Labels on the Cloud Run service (in addition to resource_labels).

§6 · CI/CD Integration

§6.A · GitHub Integration

VariableDefaultDescription
enable_cicd_triggerfalseEnables a Cloud Build trigger that automatically builds and deploys when code is pushed to the configured repository.
github_repository_url""Full HTTPS URL of the GitHub repository. Required when enable_cicd_trigger = true.
github_token""GitHub PAT for authentication. Mutually exclusive with github_app_installation_id.
github_app_installation_id""Cloud Build GitHub App installation ID. Preferred for organisation repositories.
cicd_trigger_config{ branch_pattern = "^main$" }Advanced trigger config: branch_pattern, included_files, ignored_files, trigger_name, substitutions.

§6.B · Cloud Deploy

VariableDefaultDescription
enable_cloud_deployfalseSwitches CI/CD from direct Cloud Build deployments to a managed Cloud Deploy pipeline. Requires enable_cicd_trigger = true.
cloud_deploy_stages[dev, staging, prod]Ordered promotion stages. Each stage: name, require_approval, auto_promote. prod requires approval by default.

§7 · Reliability & Data

§7.A · Health Probes

OpenEMR performs database connection validation and, on first boot, runs the full database installation process (5–20 minutes). startup_probe and liveness_probe are passed both to OpenEMR Common and — as startup_probe_config / health_check_config — directly to App CloudRun.

VariableDefaultDescription
startup_probe{ enabled = true, type = "TCP", path = "/", initial_delay_seconds = 0, timeout_seconds = 5, period_seconds = 10, failure_threshold = 12 }TCP port check during startup. More reliable than HTTP during Apache/PHP-FPM initialisation. With period_seconds = 10 and failure_threshold = 12, allows 120 s of startup time. On first deployment (full DB schema install), increase failure_threshold to 30.
liveness_probe{ enabled = true, type = "HTTP", path = "/interface/login/login.php", initial_delay_seconds = 0, timeout_seconds = 10, period_seconds = 30, failure_threshold = 10 }HTTP check on the OpenEMR login page. Returns 200 only when Apache, PHP-FPM, and the database connection are all operational. period_seconds = 30 with failure_threshold = 10 allows 5 min of recovery.

§7.B · Storage

VariableDefaultDescription
enable_nfstrueMust remain true for a functional OpenEMR deployment. Provisions Cloud Filestore NFS. OpenEMR cannot persist patient data without shared NFS storage.
nfs_mount_path"/var/www/localhost/htdocs/openemr/sites"Container mount path for the NFS volume. Maps directly to OpenEMR's sites directory. Do not change unless the container uses a different path.
nfs_instance_name""Name of an existing NFS GCE VM to use. Leave empty to auto-discover a Services GCP-managed instance.
nfs_instance_base_name"app-nfs"Base name for the inline NFS GCE VM when no existing instance is found.
storage_buckets[{ name_suffix = "data" }]GCS buckets to provision. OpenEMR Common may provision additional buckets via module_storage_buckets.
create_cloud_storagetrueSet false to skip GCS bucket provisioning.
gcs_volumes[]GCS buckets to mount as GCS Fuse volumes inside the container (passed to both OpenEMR Common and App CloudRun).
manage_storage_kms_iamfalseCreates a CMEK KMS keyring and storage encryption key, enabling CMEK on all GCS buckets.
enable_artifact_registry_cmekfalseCreates an Artifact Registry KMS key, enabling CMEK encryption of container images.

§7.C · Database

OpenEMR requires MySQL 8.0. db_name and db_user are aliases for application_database_name and application_database_user. The Cloud SQL connection uses a Unix socket at cloudsql_volume_mount_path; TCP connections are not used.

VariableDefaultDescription
db_name"openemr"MySQL database name. Injected into sqlconf.php. Do not change after initial deployment.
db_user"openemr"MySQL user. Password auto-generated and injected as MYSQL_PASS.
database_password_length32Auto-generated password length (16–64 characters).
enable_auto_password_rotationfalseAutomates password rotation via Cloud Run + Eventarc. See §4.A.
rotation_propagation_delay_sec90Seconds to wait after rotation before Cloud Run restarts.

§7.D · Backup & Recovery

backup_uri is the OpenEMR-specific name for backup_file. The mapping is applied in main.tf (backup_file = var.backup_uri). When backup_uri is set, it is also injected into the nfs-init job as BACKUP_FILEID, triggering backup restoration during deployment.

VariableDefaultDescription
backup_schedule"0 2 * * *"Cron expression (UTC) for automated backups. Leave empty to disable. Daily backups strongly recommended for healthcare data.
backup_retention_days7Days to retain backup files. Consider regulatory retention requirements before reducing.
enable_backup_importfalseTriggers backup restoration via the nfs-init job. The backup_uri value is injected as BACKUP_FILEID.
backup_source"gcs"Source: "gcs" (full GCS URI) or "gdrive" (Google Drive file ID).
backup_uri""For GCS: e.g. "gs://my-bucket/backups/openemr.sql". Mapped to backup_file in App CloudRun.
backup_format"sql"Format: sql, gz, tar, tgz, tar.gz, zip.

§8 · Integrations

§8.A · Redis Session Store

Redis is enabled by default (enable_redis = true) and is required for multi-instance deployments. Without Redis, each Cloud Run instance has its own PHP session store and clinical users lose their sessions when requests land on different instances. When redis_host is left empty, the module defaults to using the NFS server IP as the Redis host (the NFS server runs a co-located Redis instance).

VariableDefaultDescription
enable_redistrueConfigures OpenEMR to use Redis for PHP session storage. Injects REDIS_SERVER automatically. If redis_host is empty, uses the NFS server IP.
redis_host""Redis hostname or IP. Leave empty to use the NFS server IP. Override with a dedicated Cloud Memorystore instance for higher-availability production deployments.
redis_port"6379"Redis TCP port (string).
redis_auth""Redis AUTH password. Leave empty if authentication is not enabled. Treated as sensitive. Passed to App CloudRun but not OpenEMR Common.

§8.B · Custom SQL Scripts

VariableDefaultDescription
enable_custom_sql_scriptsfalseRuns .sql files from GCS against the OpenEMR MySQL database after provisioning.
custom_sql_scripts_bucket""GCS bucket name (without gs://) containing the scripts.
custom_sql_scripts_path""Path prefix within the bucket. Files run in lexicographic order; use numeric prefixes (e.g. 001_schema.sql).
custom_sql_scripts_use_rootfalseRun scripts as the root database user (for privilege-requiring operations).

§8.C · Jobs & Scheduled Tasks

User-defined initialization and cron jobs supplement the platform-managed nfs-init job (see §9). Both are passed through to App CloudRun via initialization_jobs and cron_jobs.

VariableDefaultDescription
initialization_jobs[]Cloud Run jobs executed once during deployment. Each job requires at least one of command, args, or script_path. Set mount_nfs = true for jobs that need access to the sites directory.
cron_jobs[]Recurring Cloud Scheduler-triggered jobs. Each entry requires name and schedule (cron format, UTC). Set mount_nfs = true for jobs that access patient documents.

§8.D · Observability

VariableDefaultDescription
uptime_check_config{ enabled = true, path = "/" }Cloud Monitoring uptime check. check_interval and timeout use "Ns" format.
alert_policies[]Metric-threshold alert policies. Each entry: name, metric_type, comparison, threshold_value, duration_seconds.
service_annotations{}Kubernetes-style annotations on the Cloud Run service resource.
service_labels{}Labels on the Cloud Run service (in addition to resource_labels).

§9 · Platform-Managed Behaviours

These are set automatically by the module and cannot be overridden via input variables.

Initialisation Job

JobWhat it does
nfs-initMounts the Cloud Filestore NFS share; sets ownership of the sites directory to UID 1000 (Apache process user); downloads and restores the backup if backup_uri is set (injected as BACKUP_FILEID); regenerates sqlconf.php with current database credentials. Must complete before the Cloud Run service starts.

Secrets (always injected)

VariableValue / SourceNotes
OE_PASSSecret Manager refAuto-generated OpenEMR admin password stored in Secret Manager. Used to set the administrator account on first boot.
MYSQL_PASSmodule.app_cloudrun.database_password_secretAuto-generated MySQL password from App CloudRun. Do not define this in secret_environment_variables.

Structural Wiring

BehaviourDetail
Cloud SQL Unix socketConnected via Unix socket at cloudsql_volume_mount_path = "/cloudsql". OpenEMR's sqlconf.php uses this socket path. TCP connections are not used. This is enforced unconditionally.
scripts_dirResolved as abspath("${module.openemr_app.path}/scripts") — points to OpenEMR Common's bundled scripts.
module_env_varsSourced from module.openemr_app.config.environment_variables (OpenEMR Common's resolved env vars).
startup_probestartup_probe_configvar.startup_probe is passed as startup_probe_config to App CloudRun in main.tf.
liveness_probehealth_check_configvar.liveness_probe is passed as health_check_config to App CloudRun in main.tf.
backup_uribackup_filevar.backup_uri is mapped to backup_file in main.tf. Also injected into the nfs-init job as BACKUP_FILEID.

§10 · Variable Reference

Complete list of all input variables, grouped by UI section.

GroupVariableTypeDefaultUpdatable
0module_descriptionstring(long description)
0module_documentationstring"https://docs.radmodules.dev/docs/modules/OpenEMR_CloudRun"
0module_dependencylist(string)["Services GCP"]
0module_serviceslist(string)(service list)
0credit_costnumber50
0require_credit_purchasesboolfalse
0enable_purgebooltrue
0public_accessbooltrue
0deployment_idstring""yes
0resource_creator_identitystring"rad-module-creator@…"yes
1project_idstringyes
1tenant_deployment_idstring"demo"yes
1support_userslist(string)[]yes
1resource_labelsmap(string){}yes
2application_namestring"openemr"yes
2display_namestring"OpenEMR"yes
2descriptionstring"OpenEMR Electronic Health Records on Cloud Run"yes
2application_versionstring"7.0.4"yes
3deploy_applicationbooltrueyes
3cpu_limitstring"2000m"yes
3memory_limitstring"4Gi"yes
3min_instance_countnumber1yes
3max_instance_countnumber1yes
3container_portnumber80yes
3execution_environmentstring"gen2"yes
3timeout_secondsnumber300yes
3service_annotationsmap(string){}yes
3service_labelsmap(string){}yes
3traffic_splitlist(object)[]yes
3container_protocolstring"http1"yes
3cloudsql_volume_mount_pathstring"/cloudsql"yes
3enable_image_mirroringbooltrueyes
4ingress_settingsstring"all"yes
4vpc_egress_settingstring"PRIVATE_RANGES_ONLY"yes
4enable_iapboolfalseyes
4iap_authorized_userslist(string)[]yes
4iap_authorized_groupslist(string)[]yes
5environment_variablesmap(string){}yes
5secret_environment_variablesmap(string){}yes
5secret_rotation_periodstring"2592000s"yes
5secret_propagation_delaynumber30yes
6backup_schedulestring"0 2 * * *"yes
6backup_retention_daysnumber7yes
6enable_backup_importboolfalseyes
6backup_sourcestring"gcs"yes
6backup_uristring""yes
6backup_formatstring"sql"yes
7enable_cicd_triggerboolfalseyes
7github_repository_urlstring""yes
7github_tokenstring""yes
7github_app_installation_idstring""yes
7cicd_trigger_configobject{ branch_pattern = "^main$" }yes
7enable_cloud_deployboolfalseyes
7cloud_deploy_stageslist(object)[dev, staging, prod]yes
7enable_binary_authorizationboolfalseyes
8enable_custom_sql_scriptsboolfalseyes
8custom_sql_scripts_bucketstring""yes
8custom_sql_scripts_pathstring""yes
8custom_sql_scripts_use_rootboolfalseyes
9enable_cloud_armorboolfalseyes
9admin_ip_rangeslist(string)[]yes
9application_domainslist(string)[]yes
9enable_cdnboolfalseyes
9max_images_to_retainnumber7yes
9delete_untagged_imagesbooltrueyes
9image_retention_daysnumber30yes
10create_cloud_storagebooltrueyes
10storage_bucketslist(object)[{ name_suffix = "data" }]yes
10enable_nfsbooltrueyes
10nfs_mount_pathstring"/var/www/localhost/htdocs/openemr/sites"yes
10nfs_instance_namestring""yes
10nfs_instance_base_namestring"app-nfs"yes
10gcs_volumeslist(object)[]yes
10manage_storage_kms_iamboolfalseyes
10enable_artifact_registry_cmekboolfalseyes
11db_namestring"openemr"yes
11db_userstring"openemr"yes
11database_password_lengthnumber32yes
11enable_auto_password_rotationboolfalseyes
11rotation_propagation_delay_secnumber90yes
12initialization_jobslist(object)[]yes
12cron_jobslist(object)[]yes
13startup_probeobject{ type = "TCP", initial_delay_seconds = 0, failure_threshold = 12, … }yes
13liveness_probeobject{ type = "HTTP", path = "/interface/login/login.php", failure_threshold = 10, … }yes
13uptime_check_configobject{ enabled = true, path = "/" }yes
13alert_policieslist(object)[]yes
13max_revisions_to_retainnumber7yes
20enable_redisbooltrueyes
20redis_hoststring""yes
20redis_portstring"6379"yes
20redis_authstring""yes
21enable_vpc_scboolfalseyes
21vpc_cidr_rangeslist(string)[]yes
21vpc_sc_dry_runbooltrueyes
21organization_idstring""yes
21enable_audit_loggingboolfalseyes

Configuration Pitfalls & Sensible Defaults

Risk levels: Critical (data loss, full outage, security breach) — High (service unavailable or significant degradation) — Medium (degraded function or increased cost) — Low (minor impact).

VariableSensible DefaultRiskConsequence of Incorrect Value
database_typeMYSQL_8_0CriticalOpenEMR is MySQL-only. Changing to PostgreSQL causes the initialisation job and all OpenEMR PHP code to fail immediately — OpenEMR does not support PostgreSQL.
OE_USER (hardcoded in Common)adminHighThe initial admin username is hardcoded to admin in the OpenEMR Common init job. Changing it via environment_variables after initial deployment does not rename the existing account — it creates a second account or fails silently.
OE_PASS (via Secret Manager)Auto-generated 20-character random passwordHighThe auto-generated admin password is stored in Secret Manager. Retrieve it from Secret Manager before attempting to log in. Passing a custom OE_PASS via environment_variables on an already-initialised database has no effect — OpenEMR reads the password from the database, not env vars, after setup.
MANUAL_SETUP (hardcoded in Common)noCriticalHardcoded to no, triggering automatic database initialisation via auto_configure.php. Setting to yes skips auto-setup and expects a pre-existing database schema — the service starts but presents a blank database error page until the schema is created manually.
K8S (in init job)admin (init job mode)CriticalThe init job runs with K8S=admin to perform schema creation without starting Apache. Changing this environment variable in the init job definition causes auto-setup to be skipped, leaving the database uninitialised and the service unable to start.
ephemeral_storage_limit"2Gi"HighOpenEMR writes PHP opcache, Apache logs, session files, and installation temp files to the container writable layer. The default GKE Autopilot 1Gi ephemeral storage limit is insufficient and causes the pod to be evicted. Must be at least 2Gi; set to 3–4Gi for production.
MYSQL_ROOT_PASS (via environment_variables)BLANKHighOpenEMR's init scripts use MYSQL_ROOT_PASS to create the application user. The value BLANK is a special sentinel meaning "no root password required" (Cloud SQL Auth Proxy authenticates differently). Changing this to a real value causes the init job to attempt password-based MySQL root authentication, which fails against Cloud SQL.
enable_redisfalseMediumWhen enable_redis = true, redis_host must point to a reachable Redis instance before OpenEMR starts. An unreachable Redis host causes PHP session handling to fail, preventing any user from logging in.
redis_host""HighRequired when enable_redis = true. An empty value causes OpenEMR session handling to attempt connection to an empty hostname, producing PHP warnings and login failures for all users.
enable_nfs (via NFS mount for sites dir)NFS required for multi-instanceHighOpenEMR stores the sites/ directory (documents, configuration) on NFS for multi-instance setups. Without NFS, each Cloud Run instance has its own isolated sites/ directory — patient documents uploaded to one instance are invisible on others, and configuration changes are not shared.
min_instance_count1HighSetting to 0 enables scale-to-zero. OpenEMR has a slow cold-start (Apache + PHP-FPM initialisation typically takes 20–40 seconds). Scale-to-zero causes unacceptable delays for clinical workflows where response time is critical.
cpu_limit1000mHighOpenEMR runs Apache + PHP-FPM with multiple worker processes. Under concurrent load, insufficient CPU causes PHP worker timeouts and Apache 503 errors. 2000m is recommended for production deployments with multiple concurrent users.
memory_limit1GiHighOpenEMR's PHP processes are memory-intensive (patient record loading, PDF generation, billing processing). Less than 512Mi causes PHP-FPM worker OOM kills mid-request; 1Gi is the minimum for reliable single-user operation.
execution_environment"gen2"HighGen2 is required for NFS mounts needed by the OpenEMR sites directory. Gen1 does not support Unix socket paths in the expected Cloud SQL Auth Proxy location, causing both NFS and database connection failures.
enable_cloudsql_volumetrueCriticalOpenEMR connects to Cloud SQL via the Auth Proxy Unix socket. Disabling this causes all MySQL connections to fail at startup — OpenEMR cannot function without database access.
backup_schedule"0 2 * * *"CriticalAn empty string disables automated backups entirely. OpenEMR contains protected health information (PHI). Without automated backups, a Cloud SQL failure results in permanent loss of patient records — a HIPAA compliance violation. Always configure a backup schedule.
backup_retention_days7MediumSetting to 0 or 1 reduces the recovery window for accidental data deletion or corruption. For HIPAA-regulated environments, retain at least 90 days of backups.
enable_iapfalseMediumEnabling IAP without setting iap_oauth_client_id and iap_oauth_client_secret causes a partial IAP configuration that may leave the service inaccessible or unprotected. For clinical deployments, consider IAP to restrict access to authorised staff only.
timeout_seconds300MediumOpenEMR's billing and reporting features generate large PDFs that can exceed 60 seconds. A timeout below 120 seconds causes these operations to fail mid-execution. Increase to 600+ for production deployments.
enable_vpc_scfalseHighRequires explicit organization_id. Without it, VPC Service Controls are silently skipped. For HIPAA environments, VPC-SC is a key control for preventing data exfiltration.
enable_auto_password_rotationfalseMediumWhen enabled, the Cloud SQL password rotates on schedule. The Cloud Run revision must be redeployed after rotation; otherwise OpenEMR uses an invalid MySQL password until connections fail and the service becomes unavailable.

Destroying Resources

Known Deletion Issue: Serverless IPv4 Address Release

When destroying a Cloud Run deployment, you may encounter an error similar to:

Error: Error waiting for Subnetwork to be deleted: The following serverless IPv4 address(es) on subnet ... are still in use.

Cause: GCP holds serverless IPv4 addresses on the VPC subnet asynchronously after a Cloud Run service is deleted. These addresses are released by GCP approximately 20–30 minutes after the Cloud Run service is removed. Terraform/OpenTofu cannot complete the subnet or VPC deletion until they are fully released.

Resolution: Wait 20–30 minutes after the initial destroy attempt, then re-run the destroy command:

tofu destroy

The second run will succeed once GCP has released the reserved addresses.