A containerized deployment of the AKTIN emergency department system using Docker Compose, consisting of:
- PostgreSQL database with i2b2/AKTIN schema
- WildFly application server
- Apache2 reverse proxy with i2b2 webclient
- Download the compose file:
curl -LO https://github.com/aktin/docker-aktin-dwh/releases/latest/download/compose.yml- In the folder of the
compose.ymlscript create a secret file with a strong password:
echo 'mysecretpassword' > secret.txt- Start the containers:
docker compose up -dThe system will be available at http://localhost once all containers have started. The AKTIN I2B2 can be reached at http://localhost/webclient and the DWH manager at http://localhost/aktin/admin. For bind mounts, the property files must be copied manually into the aktin_config folder. See this issue for details.
To run multiple AKTIN instances on the same server, place instances of compose.yml in separate folders and assign unique ports per instance (HTTP_PORT). Docker Compose will automatically use the folder name as the project name, isolating container names, networks, and volumes. You can configure the individual instances using .env files:
/opt/docker-deploy/aktin1/.env:
HTTP_PORT=80/opt/docker-deploy/aktin2/.env:
HTTP_PORT=81Start each instance with:
# Instance 1
cd /opt/docker-deploy/aktin1
docker compose up -d
# Instance 2
cd /opt/docker-deploy/aktin2
docker compose up -dAll our Docker images are cryptographically signed using Cosign and come with attached SBOMs (CycloneDX) and build provenance attestations (SLSA). You can check that what you run matches what we built:
Check cosign installation. If needed, install it following this instruction.
cosign version
# Example output:
# GitVersion: v2.5.3Pull the image first:
docker pull ghcr.io/aktin/notaufnahme-dwh-<service>:<tag>
# Example command:
# docker pull ghcr.io/aktin/notaufnahme-dwh-database:1.6rc1-2-docker3Inspect to find the exact digest:
docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/aktin/notaufnahme-dwh-<service>:<tag>
# Example command:
# docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/aktin/notaufnahme-dwh-database:1.6rc1-2-docker3
# Example output:
# ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363dCheck that the image was built by our GitHub Actions workflow and signed via Sigstore. If valid, you’ll see output confirming the signature and the trusted GitHub Repo. For more information, refer to the OIDC Cheat Sheet and the official Documentation. Alternatively, you can verify the digest online using the Rekor Web UI.
cosign verify \
--certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/aktin/notaufnahme-dwh-<service>@<digest>
# Example command:
# cosign verify \
# --certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
# --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
# ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363d
# Example output:
# Verification for ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363d --
# The following checks were performed on each of these signatures:
# - The cosign claims were validated
# - Existence of the claims in the transparency log was verified offline
# - The code-signing certificate was verified using trusted certificate authority certificatesEach image has an attached Software Bill of Materials. The following command prints the SBOM in JSON. This prints the CycloneDX SBOM in JSON. You can then parse it with SBOM tooling or import it into vulnerability scanners.
cosign verify-attestation \
--type cyclonedx \
--certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/aktin/notaufnahme-dwh-<service>@<digest>
# Example command:
# cosign verify-attestation \
# --type cyclonedx \
# --certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
# --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
# ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363d
# Example output:
# {"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI...","signatures":[{"keyid":"","sig":"MEYCIQC..."}]}Build provenance attestation proves the image was built from scratch in GitHub. The result will show the Git commit and build metadata. You can then trace the build back to our public repository.
cosign verify-attestation \
--type slsaprovenance1 \
--certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/aktin/notaufnahme-dwh-<service>@<digest>
# Example command:
# cosign verify-attestation \
# --type slsaprovenance1 \
# --certificate-identity-regexp "^https://github\.com/aktin/docker-aktin-dwh/\.github/workflows/.*" \
# --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
# ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363d
# Example output:
# {"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI...","signatures":[{"keyid":"","sig":"MEUCIQC..."}]}The SBOM and build provenance are published as in-toto attestations wrapped in DSSE envelopes. The actual attestation content is base64-encoded in the payload field of the JSON output. You can download the attestations directly from the OCI registry and decode the embedded payload using the following command. The resulting file will contain both the SBOM and the SLSA provenance:
cosign download attestation ghcr.io/aktin/notaufnahme-dwh-<service>@<digest> | jq -r '.payload' | base64 -d | jq > output.json
# Example command:
# cosign download attestation ghcr.io/aktin/notaufnahme-dwh-database@sha256:3568fccb80c6f3512eb865d072ed76df7ebe35a2f6784eaad737e8b6e6e3363d | jq -r '.payload' | base64 -d | jq > output.jsonIf you want to build the containers yourself or contribute to development:
- Clone this repository:
git clone https://github.com/aktin/docker-aktin-dwh.git
cd docker-aktin-dwh - Set the required
DEV_API_KEYenvironment variable:
export DEV_API_KEY="<your-development-api-key>"Alternatively, you can create a .env file in the project root:
echo "DEV_API_KEY=<your-development-api-key>" > .env
source .env- Run the build script:
DEV_API_KEY="<your-development-api-key>" ./src/build.shThe build script accepts the following arguments:
--cleanup: Remove build files and downloads after image creation--force-rebuild: Force a complete image recreation--use-main-branch: Use current version from main branch instead of release versions--create-latest: Create additional containers tagged as 'latest'
- Run the container locally after the build finished using:
cd build/
docker compose -f compose.dev.yml up -d The WildFly Docker container can run in development mode using the DEV_MODE environment variable. When set, the WildFly Docker will use a customized configuration file and mount a separate volume to /opt/wildfly/standalone/deployments to allow for isolated development deployments. DEV_MODE=true is set by default in the compose.dev.yml.
- Image:
notaufnahme-dwh-database - Provides preconfigured database environment for i2b2 and AKTIN
- Volume mounted at
/var/lib/postgresql/data
- Image:
notaufnahme-dwh-wildfly - Java application server with i2b2 and AKTIN components
- Includes Python and R data processing capabilities
- Volumes mounted at
/etc/aktinand/var/lib/aktin
- Image:
notaufnahme-dwh-httpd - Provides i2b2 web interface and reverse proxy configuration
- Default port: 80 (configurable via
HTTP_PORTenvironment variable)
These variables can be defined in a .env file and are used throughout compose.yml to configure the system:
HTTP_PORT: Exposed port for the Apache HTTPD server (default:80)DB_HOST: Hostname of the database container (default:database)DB_PORT: Port to reach PostgreSQL (default:5432)DEV_MODE: Enables WildFly dev mode (default:false)