{
  "manifest_version": "1.0.0",
  "template": {
    "id": "7d1983cb-3da6-4c03-82e4-0016bbf206d5",
    "slug": "hapi-fhir-server",
    "name": "HAPI FHIR server",
    "description": "Protected HAPI FHIR R4 server with durable PostgreSQL storage.",
    "url": "https://railway.com/deploy/hapi-fhir-server",
    "upstream": {
      "image": "caddy:2.11.4-alpine@sha256:5f5c8640aae01df9654968d946d8f1a56c497f1dd5c5cda4cf95ab7c14d58648"
    }
  },
  "services": [
    {
      "name": "HAPI FHIR",
      "source": {
        "image": "hapiproject/hapi:v8.10.0-3@sha256:55213612779ab3eeec919226b7bad378f0061ade823393a61d7dd46dd5087a3d"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "FHIR Gateway",
      "source": {
        "image": "caddy:2.11.4-alpine@sha256:5f5c8640aae01df9654968d946d8f1a56c497f1dd5c5cda4cf95ab7c14d58648"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "HAPI PostgreSQL",
      "source": {
        "image": "postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "PORT",
      "service": "HAPI FHIR",
      "description": "Private HAPI FHIR HTTP listener.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "HIBERNATE_DIALECT",
      "service": "HAPI FHIR",
      "description": "HAPI FHIR PostgreSQL schema dialect.",
      "secret": false,
      "strategy": "default",
      "default": "ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgresDialect"
    },
    {
      "key": "JAVA_TOOL_OPTIONS",
      "service": "HAPI FHIR",
      "description": "Bounds the JVM heap relative to Railway's service memory.",
      "secret": false,
      "strategy": "default",
      "default": "-XX:InitialRAMPercentage=15.0 -XX:MaxRAMPercentage=55.0"
    },
    {
      "key": "SPRING_DATASOURCE_URL",
      "service": "HAPI FHIR",
      "description": "Private PostgreSQL JDBC URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "HAPI_FHIR_FHIR_VERSION",
      "service": "HAPI FHIR",
      "description": "Pins the server API and model to FHIR R4.",
      "secret": false,
      "strategy": "default",
      "default": "R4"
    },
    {
      "key": "HAPI_FHIR_SERVER_ADDRESS",
      "service": "HAPI FHIR",
      "description": "Public FHIR base URL used for generated absolute resource links.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "SPRING_DATASOURCE_PASSWORD",
      "service": "HAPI FHIR",
      "description": "Generated PostgreSQL password shared by the database service.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SPRING_DATASOURCE_USERNAME",
      "service": "HAPI FHIR",
      "description": "PostgreSQL application user.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SERVER_FORWARD_HEADERS_STRATEGY",
      "service": "HAPI FHIR",
      "description": "Honors Railway and Caddy forwarding headers when constructing links.",
      "secret": false,
      "strategy": "default",
      "default": "framework"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "HAPI FHIR",
      "description": "Allows in-flight requests to finish during deploys.",
      "secret": false,
      "strategy": "default",
      "default": "30"
    },
    {
      "key": "SPRING_DATASOURCE_DRIVER_CLASS_NAME",
      "service": "HAPI FHIR",
      "description": "Official PostgreSQL JDBC driver.",
      "secret": false,
      "strategy": "default",
      "default": "org.postgresql.Driver"
    },
    {
      "key": "HAPI_FHIR_TESTER_HOME_SERVER_ADDRESS",
      "service": "HAPI FHIR",
      "description": "Authenticated public FHIR base URL shown in the test UI.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "HAPI_FHIR_TESTER_HOME_REFUSE_TO_FETCH_THIRD_PARTY_URLS",
      "service": "HAPI FHIR",
      "description": "Prevents the web tester from fetching arbitrary remote FHIR servers.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PORT",
      "service": "FHIR Gateway",
      "description": "Caddy listener exposed through the Railway domain.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "CADDY_CONFIG",
      "service": "FHIR Gateway",
      "description": "Audited gateway policy that leaves only health anonymous and strips the shared credential upstream.",
      "secret": false,
      "strategy": "default",
      "default": ":8080 {\n  handle_path /healthz {\n    rewrite * /actuator/health/readiness\n    reverse_proxy http://__UPSTREAM__\n  }\n  @protected not path /healthz\n  basic_auth @protected {\n    __USERNAME__ __PASSWORD_HASH__\n  }\n  reverse_proxy http://__UPSTREAM__ {\n    header_up -Authorization\n  }\n}"
    },
    {
      "key": "FHIR_PASSWORD",
      "service": "FHIR Gateway",
      "description": "Generated Basic Auth password; store it securely and rotate deliberately.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "FHIR_UPSTREAM",
      "service": "FHIR Gateway",
      "description": "Private HAPI FHIR server endpoint.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "FHIR_USERNAME",
      "service": "FHIR Gateway",
      "description": "Basic Auth username protecting every FHIR and UI route.",
      "secret": false,
      "strategy": "default",
      "default": "admin"
    },
    {
      "key": "PGDATA",
      "service": "HAPI PostgreSQL",
      "description": "Nested PostgreSQL data directory suitable for the mounted Railway volume.",
      "secret": false,
      "strategy": "default",
      "default": "/var/lib/postgresql/data/pgdata"
    },
    {
      "key": "POSTGRES_DB",
      "service": "HAPI PostgreSQL",
      "description": "Database created for HAPI FHIR.",
      "secret": false,
      "strategy": "default",
      "default": "hapi"
    },
    {
      "key": "POSTGRES_USER",
      "service": "HAPI PostgreSQL",
      "description": "Database role created for HAPI FHIR.",
      "secret": false,
      "strategy": "default",
      "default": "hapi"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "HAPI PostgreSQL",
      "description": "Generated database password referenced by HAPI FHIR.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "hapi-fhir-server"
      }
    },
    "cli": "railway deploy --template hapi-fhir-server",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "7d1983cb-3da6-4c03-82e4-0016bbf206d5",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "1cd679e1-9426-49c7-91bc-16ec8ae4e984": {
                  "icon": null,
                  "name": "HAPI FHIR",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": "/fhir/metadata",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "hapiproject/hapi:v8.10.0-3@sha256:55213612779ab3eeec919226b7bad378f0061ade823393a61d7dd46dd5087a3d"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Private HAPI FHIR HTTP listener.",
                      "defaultValue": "8080"
                    },
                    "HIBERNATE_DIALECT": {
                      "isOptional": false,
                      "description": "HAPI FHIR PostgreSQL schema dialect.",
                      "defaultValue": "ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgresDialect"
                    },
                    "JAVA_TOOL_OPTIONS": {
                      "isOptional": false,
                      "description": "Bounds the JVM heap relative to Railway's service memory.",
                      "defaultValue": "-XX:InitialRAMPercentage=15.0 -XX:MaxRAMPercentage=55.0"
                    },
                    "SPRING_DATASOURCE_URL": {
                      "isOptional": false,
                      "description": "Private PostgreSQL JDBC URL.",
                      "defaultValue": "jdbc:postgresql://${{HAPI PostgreSQL.RAILWAY_PRIVATE_DOMAIN}}:5432/${{HAPI PostgreSQL.POSTGRES_DB}}"
                    },
                    "HAPI_FHIR_FHIR_VERSION": {
                      "isOptional": false,
                      "description": "Pins the server API and model to FHIR R4.",
                      "defaultValue": "R4"
                    },
                    "HAPI_FHIR_SERVER_ADDRESS": {
                      "isOptional": false,
                      "description": "Public FHIR base URL used for generated absolute resource links.",
                      "defaultValue": "https://${{FHIR Gateway.RAILWAY_PUBLIC_DOMAIN}}/fhir"
                    },
                    "SPRING_DATASOURCE_PASSWORD": {
                      "isOptional": false,
                      "description": "Generated PostgreSQL password shared by the database service.",
                      "defaultValue": "${{HAPI PostgreSQL.POSTGRES_PASSWORD}}"
                    },
                    "SPRING_DATASOURCE_USERNAME": {
                      "isOptional": false,
                      "description": "PostgreSQL application user.",
                      "defaultValue": "${{HAPI PostgreSQL.POSTGRES_USER}}"
                    },
                    "SERVER_FORWARD_HEADERS_STRATEGY": {
                      "isOptional": false,
                      "description": "Honors Railway and Caddy forwarding headers when constructing links.",
                      "defaultValue": "framework"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": false,
                      "description": "Allows in-flight requests to finish during deploys.",
                      "defaultValue": "30"
                    },
                    "SPRING_DATASOURCE_DRIVER_CLASS_NAME": {
                      "isOptional": false,
                      "description": "Official PostgreSQL JDBC driver.",
                      "defaultValue": "org.postgresql.Driver"
                    },
                    "HAPI_FHIR_TESTER_HOME_SERVER_ADDRESS": {
                      "isOptional": false,
                      "description": "Authenticated public FHIR base URL shown in the test UI.",
                      "defaultValue": "https://${{FHIR Gateway.RAILWAY_PUBLIC_DOMAIN}}/fhir"
                    },
                    "HAPI_FHIR_TESTER_HOME_REFUSE_TO_FETCH_THIRD_PARTY_URLS": {
                      "isOptional": false,
                      "description": "Prevents the web tester from fetching arbitrary remote FHIR servers.",
                      "defaultValue": "true"
                    }
                  }
                },
                "a9b86c19-72b5-42cb-829c-ba5130a90cc2": {
                  "icon": null,
                  "name": "FHIR Gateway",
                  "deploy": {
                    "startCommand": "/bin/sh -ec 'password_hash=\"$(caddy hash-password --plaintext \"$FHIR_PASSWORD\")\"; printf \"%s\\n\" \"$CADDY_CONFIG\" | sed -e \"s|__USERNAME__|$FHIR_USERNAME|g\" -e \"s|__PASSWORD_HASH__|$password_hash|g\" -e \"s|__UPSTREAM__|$FHIR_UPSTREAM|g\" >/tmp/Caddyfile; exec caddy run --config /tmp/Caddyfile --adapter caddyfile'",
                    "healthcheckPath": "/healthz",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "caddy:2.11.4-alpine@sha256:5f5c8640aae01df9654968d946d8f1a56c497f1dd5c5cda4cf95ab7c14d58648"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Caddy listener exposed through the Railway domain.",
                      "defaultValue": "8080"
                    },
                    "CADDY_CONFIG": {
                      "isOptional": false,
                      "description": "Audited gateway policy that leaves only health anonymous and strips the shared credential upstream.",
                      "defaultValue": ":8080 {\n  handle_path /healthz {\n    rewrite * /actuator/health/readiness\n    reverse_proxy http://__UPSTREAM__\n  }\n  @protected not path /healthz\n  basic_auth @protected {\n    __USERNAME__ __PASSWORD_HASH__\n  }\n  reverse_proxy http://__UPSTREAM__ {\n    header_up -Authorization\n  }\n}"
                    },
                    "FHIR_PASSWORD": {
                      "isOptional": false,
                      "description": "Generated Basic Auth password; store it securely and rotate deliberately.",
                      "defaultValue": "{{FHIR_PASSWORD}}"
                    },
                    "FHIR_UPSTREAM": {
                      "isOptional": false,
                      "description": "Private HAPI FHIR server endpoint.",
                      "defaultValue": "${{HAPI FHIR.RAILWAY_PRIVATE_DOMAIN}}:8080"
                    },
                    "FHIR_USERNAME": {
                      "isOptional": false,
                      "description": "Basic Auth username protecting every FHIR and UI route.",
                      "defaultValue": "admin"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>": {
                        "port": 8080
                      }
                    }
                  }
                },
                "d5457e08-0002-4eb6-a2fe-cd191366d449": {
                  "icon": null,
                  "name": "HAPI PostgreSQL",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": null,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777"
                  },
                  "variables": {
                    "PGDATA": {
                      "isOptional": false,
                      "description": "Nested PostgreSQL data directory suitable for the mounted Railway volume.",
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "POSTGRES_DB": {
                      "isOptional": false,
                      "description": "Database created for HAPI FHIR.",
                      "defaultValue": "hapi"
                    },
                    "POSTGRES_USER": {
                      "isOptional": false,
                      "description": "Database role created for HAPI FHIR.",
                      "defaultValue": "hapi"
                    },
                    "POSTGRES_PASSWORD": {
                      "isOptional": false,
                      "description": "Generated database password referenced by HAPI FHIR.",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "d5457e08-0002-4eb6-a2fe-cd191366d449": {
                      "sizeMB": 5000,
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "FHIR Gateway",
      "method": "GET",
      "path": "/healthz",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 3,
    "needs_volume": true
  },
  "generated_at": "2026-09-10T16:14:52.212Z",
  "generator_version": "0.1.0",
  "status": "validated",
  "validated_at": "2026-09-06T00:02:09.770Z",
  "success_rate_30d": 1,
  "validation": {
    "last_run_id": "run_6959631c6e9644258777",
    "checks": [
      {
        "name": "workflow_completed",
        "passed": true
      },
      {
        "name": "all_services_deployed",
        "passed": true
      },
      {
        "name": "healthcheck",
        "passed": true
      },
      {
        "name": "stays_up",
        "passed": true
      }
    ],
    "typical_ready_seconds": 194,
    "typical_build_seconds": 0,
    "typical_start_seconds": 71,
    "slowest_service": "FHIR Gateway"
  }
}
