init: sudah ganti logo, hilangin setting, dan investigational use dialog
This commit is contained in:
6
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/.gitignore
vendored
Normal file
6
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
logs/*
|
||||
volumes/*
|
||||
config/letsencrypt/*
|
||||
config/certbot/*
|
||||
!config/letsencrypt/.gitkeep
|
||||
!config/certbot/.gitkeep
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Start oauth2-proxy
|
||||
oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg &
|
||||
|
||||
# Start nginx
|
||||
nginx -g "daemon off;"
|
||||
238
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf
Normal file
238
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf
Normal file
@@ -0,0 +1,238 @@
|
||||
worker_processes auto;
|
||||
error_log /var/logs/nginx/error.log debug;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include '/etc/nginx/mime.types';
|
||||
default_type application/octet-stream;
|
||||
|
||||
keepalive_timeout 65;
|
||||
keepalive_requests 100000;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
proxy_buffers 16 16k;
|
||||
proxy_buffer_size 32k;
|
||||
proxy_busy_buffers_size 64k;
|
||||
proxy_max_temp_file_size 128k;
|
||||
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name YOUR_DOMAIN;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name YOUR_DOMAIN;
|
||||
ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
|
||||
root /var/www/html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||
gzip_comp_level 9;
|
||||
etag on;
|
||||
|
||||
location /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
proxy_cache_bypass $http_pragma;
|
||||
proxy_cache_revalidate on;
|
||||
expires off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
|
||||
location /oauth2 {
|
||||
expires -1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Auth-Request-Redirect $request_uri;
|
||||
proxy_pass http://localhost:4180$uri$is_args$args;
|
||||
}
|
||||
|
||||
location /oauth2/callback {
|
||||
proxy_pass http://localhost:4180;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /oauth2/sign_out {
|
||||
expires -1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Auth-Request-Redirect /oauth2/sign_in;
|
||||
proxy_pass http://localhost:4180;
|
||||
}
|
||||
|
||||
|
||||
location /pacs/ {
|
||||
auth_request /oauth2/auth;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept' always;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
rewrite ^/pacs/(.*) /dcm4chee-arc/aets/DCM4CHEE/rs/$1 break;
|
||||
proxy_pass http://arc:8080;
|
||||
}
|
||||
|
||||
location /pacs-admin {
|
||||
return 301 /pacs-admin/;
|
||||
}
|
||||
|
||||
# Redirect /pacs-admin to /dcm4chee-arc/ui2/
|
||||
location = /pacs-admin {
|
||||
return 301 $scheme://$host/dcm4chee-arc/ui2/;
|
||||
}
|
||||
|
||||
# Handle /pacs-admin/ requests
|
||||
location /pacs-admin/ {
|
||||
return 301 $scheme://$host/dcm4chee-arc/ui2/;
|
||||
}
|
||||
|
||||
# Proxy pass for /dcm4chee-arc/ui2/
|
||||
location /dcm4chee-arc/ui2/ {
|
||||
error_page 401 = /oauth2/sign_in?rd=$scheme://$host$request_uri;
|
||||
auth_request /oauth2/auth?allowed_groups=pacsadmin;
|
||||
|
||||
auth_request_set $user $upstream_http_x_auth_request_user;
|
||||
auth_request_set $token $upstream_http_x_auth_request_access_token;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
|
||||
proxy_set_header X-User $user;
|
||||
proxy_set_header X-Access-Token $token;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept' always;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
proxy_pass http://arc:8080;
|
||||
}
|
||||
|
||||
# Proxy pass for other /dcm4chee-arc/ requests
|
||||
location /dcm4chee-arc/ {
|
||||
proxy_pass http://arc:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
|
||||
location /pacs {
|
||||
return 301 /pacs/;
|
||||
}
|
||||
|
||||
|
||||
location /ohif-viewer/ {
|
||||
expires -1;
|
||||
error_page 401 = /oauth2/sign_in?rd=$scheme://$host$request_uri;
|
||||
auth_request /oauth2/auth;
|
||||
|
||||
auth_request_set $user $upstream_http_x_auth_request_user;
|
||||
auth_request_set $token $upstream_http_x_auth_request_access_token;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
|
||||
proxy_set_header X-User $user;
|
||||
proxy_set_header X-Access-Token $token;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Server $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
|
||||
location /ohif-viewer {
|
||||
return 301 /ohif-viewer/;
|
||||
}
|
||||
|
||||
location = / {
|
||||
return 301 /ohif-viewer/;
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
location /keycloak/ {
|
||||
proxy_pass http://keycloak:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /keycloak {
|
||||
return 301 /keycloak/;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
http_address="0.0.0.0:4180"
|
||||
cookie_secret="GENERATEACOOKIESECRET----------------------="
|
||||
email_domains=["*"]
|
||||
cookie_secure="false"
|
||||
cookie_expire="9m30s"
|
||||
cookie_refresh="5m"
|
||||
client_secret="2Xtlde7aozdkzzYHdIxQNfPDr0wNPTgg"
|
||||
client_id="ohif_viewer"
|
||||
redirect_url="http://YOUR_DOMAIN/oauth2/callback"
|
||||
|
||||
ssl_insecure_skip_verify = true
|
||||
insecure_oidc_allow_unverified_email = true
|
||||
pass_access_token = true
|
||||
provider="keycloak-oidc"
|
||||
provider_display_name="Keycloak"
|
||||
user_id_claim="oid"
|
||||
oidc_email_claim="sub"
|
||||
scope="openid"
|
||||
pass_host_header=true
|
||||
code_challenge_method="S256"
|
||||
oidc_issuer_url="http://YOUR_DOMAIN/keycloak/realms/ohif"
|
||||
insecure_oidc_skip_issuer_verification = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
STORAGE_DIR=/storage/fs1
|
||||
POSTGRES_DB=pacsdb
|
||||
POSTGRES_USER=pacs
|
||||
POSTGRES_PASSWORD=pacs
|
||||
161
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/docker-compose.yml
Normal file
161
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/docker-compose.yml
Normal file
@@ -0,0 +1,161 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
ldap:
|
||||
image: dcm4che/slapd-dcm4chee:2.6.3-29.0
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "389:389"
|
||||
env_file: docker-compose.env
|
||||
volumes:
|
||||
- ~/dcm4chee-arc/ldap:/var/lib/ldap
|
||||
- ~/dcm4chee-arc/slapd.d:/etc/ldap/slapd.d
|
||||
|
||||
db:
|
||||
image: dcm4che/postgres-dcm4chee:14.5-29
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env_file: docker-compose.env
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ~/dcm4chee-arc/db:/var/lib/postgresql/data
|
||||
|
||||
arc:
|
||||
image: dcm4che/dcm4chee-arc-psql:5.29.0
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8443:8443"
|
||||
- "9990:9990"
|
||||
- "9993:9993"
|
||||
- "11112:11112"
|
||||
- "2762:2762"
|
||||
- "2575:2575"
|
||||
- "12575:12575"
|
||||
env_file: docker-compose.env
|
||||
environment:
|
||||
WILDFLY_CHOWN: /opt/wildfly/standalone /storage
|
||||
WILDFLY_WAIT_FOR: ldap:389 db:5432
|
||||
depends_on:
|
||||
- ldap
|
||||
- db
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ~/dcm4chee-arc/wildfly:/opt/wildfly/standalone
|
||||
- ~/dcm4chee-arc/storage:/storage
|
||||
|
||||
ohif_viewer:
|
||||
build:
|
||||
context: ./../../../../
|
||||
dockerfile: ./platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile
|
||||
image: webapp:latest
|
||||
container_name: webapp
|
||||
ports:
|
||||
- '443:443' # SSL
|
||||
- '80:80' # Web
|
||||
depends_on:
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
restart: on-failure
|
||||
networks:
|
||||
- default
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
environment:
|
||||
- OAUTH2_PROXY_SKIP_PROVIDER_BUTTON=true
|
||||
volumes:
|
||||
- ./config/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./config/oauth2-proxy.cfg:/etc/oauth2-proxy/oauth2-proxy.cfg
|
||||
- ./config/letsencrypt:/etc/letsencrypt
|
||||
- ./config/certbot:/var/www/certbot
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:24.0.5
|
||||
command: 'start-dev --import-realm'
|
||||
hostname: keycloak
|
||||
container_name: keycloak
|
||||
volumes:
|
||||
- ./config/ohif-keycloak-realm.json:/opt/keycloak/data/import/ohif-keycloak-realm.json
|
||||
environment:
|
||||
KC_DB_URL_HOST: postgres
|
||||
KC_DB: postgres
|
||||
KC_DB_URL: 'jdbc:postgresql://postgres:5432/keycloak'
|
||||
KC_DB_SCHEMA: public
|
||||
KC_DB_USERNAME: keycloak
|
||||
KC_DB_PASSWORD: password
|
||||
KC_HOSTNAME_ADMIN_URL: http://YOUR_DOMAIN/keycloak/
|
||||
KC_HOSTNAME_URL: http://YOUR_DOMAIN/keycloak/
|
||||
KC_HOSTNAME_STRICT_BACKCHANNEL: true
|
||||
KC_HOSTNAME_STRICT_HTTPS: false
|
||||
KC_HTTP_ENABLED: true
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: admin
|
||||
KC_HEALTH_ENABLED: true
|
||||
KC_METRICS_ENABLED: true
|
||||
KC_PROXY: edge
|
||||
KC_PROXY_HEADERS: xforwarded
|
||||
KEYCLOAK_JDBC_PARAMS: connectTimeout=40000
|
||||
KC_LOG_LEVEL: INFO
|
||||
KC_HOSTNAME_DEBUG: true
|
||||
PROXY_ADDRESS_FORWARDING: true
|
||||
ports:
|
||||
- 8081:8080
|
||||
depends_on:
|
||||
- postgres
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"exec 3<>/dev/tcp/YOUR_DOMAIN/8080;echo -e \"GET /health/ready HTTP/1.1\r\nhost: http://localhost\r\nConnection: close\r\n\r\n\" >&3;grep \"HTTP/1.1 200 OK\" <&3"
|
||||
]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
hostname: postgres
|
||||
container_name: postgres
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: keycloak
|
||||
POSTGRES_USER: keycloak
|
||||
POSTGRES_PASSWORD: password
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
|
||||
certbot:
|
||||
image: certbot/certbot
|
||||
container_name: certbot
|
||||
volumes:
|
||||
- ./config/letsencrypt:/etc/letsencrypt
|
||||
- ./config/certbot:/var/www/certbot
|
||||
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
50
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile
Normal file
50
platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile
Normal file
@@ -0,0 +1,50 @@
|
||||
# Stage 1: Build the application
|
||||
FROM node:20.18.1-slim as builder
|
||||
|
||||
# Setup the working directory
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y build-essential python3
|
||||
|
||||
# Copy the entire project
|
||||
COPY ./ /usr/src/app/
|
||||
|
||||
# Install node dependencies
|
||||
RUN yarn config set workspaces-experimental true
|
||||
RUN yarn install
|
||||
|
||||
# Set the environment for the build
|
||||
ENV APP_CONFIG=config/docker-nginx-dcm4chee-keycloak.js
|
||||
|
||||
# Build the application
|
||||
RUN yarn run build
|
||||
|
||||
# Stage 2: Setup the NGINX environment with OAuth2 Proxy
|
||||
FROM nginx:alpine
|
||||
|
||||
# Install dependencies for oauth2-proxy
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p /var/logs/nginx /var/www/html /etc/oauth2-proxy
|
||||
|
||||
# Download and install oauth2-proxy
|
||||
RUN curl -L https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.4.0/oauth2-proxy-v7.4.0.linux-amd64.tar.gz -o oauth2-proxy.tar.gz && \
|
||||
tar -xvzf oauth2-proxy.tar.gz && \
|
||||
mv oauth2-proxy-v7.4.0.linux-amd64/oauth2-proxy /usr/local/bin/ && \
|
||||
rm -rf oauth2-proxy-v7.4.0.linux-amd64 oauth2-proxy.tar.gz
|
||||
|
||||
# Copy the built application
|
||||
COPY --from=builder /usr/src/app/platform/app/dist /var/www/html
|
||||
|
||||
# Copy the entrypoint script
|
||||
COPY ./platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Expose necessary ports
|
||||
EXPOSE 80 443 4180
|
||||
|
||||
# Set the entrypoint script as the entrypoint
|
||||
RUN chmod +x /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
@@ -0,0 +1 @@
|
||||
America/New_York
|
||||
84
platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf
Normal file
84
platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf
Normal file
@@ -0,0 +1,84 @@
|
||||
worker_processes auto;
|
||||
error_log /var/logs/nginx/error.log debug;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/logs/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
|
||||
# Handle /pacs requests and rewrite them to the correct dcm4chee-arc UI path
|
||||
# This allows accessing the dcm4chee-arc UI through the /pacs URL
|
||||
location /pacs {
|
||||
rewrite ^/pacs(.*)$ /dcm4chee-arc/ui2$1 break;
|
||||
proxy_pass http://arc:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
}
|
||||
|
||||
# Proxy all dcm4chee-arc requests
|
||||
# This block handles all API requests and general dcm4chee-arc paths
|
||||
location /dcm4chee-arc/ {
|
||||
proxy_pass http://arc:8080/dcm4chee-arc/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
|
||||
location /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
proxy_cache_bypass $http_pragma;
|
||||
proxy_cache_revalidate on;
|
||||
expires off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
}
|
||||
}
|
||||
4
platform/app/.recipes/Nginx-Dcm4chee/docker-compose.env
Normal file
4
platform/app/.recipes/Nginx-Dcm4chee/docker-compose.env
Normal file
@@ -0,0 +1,4 @@
|
||||
STORAGE_DIR=/storage/fs1
|
||||
POSTGRES_DB=pacsdb
|
||||
POSTGRES_USER=pacs
|
||||
POSTGRES_PASSWORD=pacs
|
||||
73
platform/app/.recipes/Nginx-Dcm4chee/docker-compose.yml
Normal file
73
platform/app/.recipes/Nginx-Dcm4chee/docker-compose.yml
Normal file
@@ -0,0 +1,73 @@
|
||||
services:
|
||||
ldap:
|
||||
image: dcm4che/slapd-dcm4chee:2.6.3-29.0
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "389:389"
|
||||
env_file: docker-compose.env
|
||||
volumes:
|
||||
- ~/dcm4chee-arc/ldap:/var/lib/ldap
|
||||
- ~/dcm4chee-arc/slapd.d:/etc/ldap/slapd.d
|
||||
db:
|
||||
image: dcm4che/postgres-dcm4chee:14.5-29
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env_file: docker-compose.env
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ~/dcm4chee-arc/db:/var/lib/postgresql/data
|
||||
arc:
|
||||
image: dcm4che/dcm4chee-arc-psql:5.29.0
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8443:8443"
|
||||
- "9990:9990"
|
||||
- "9993:9993"
|
||||
- "11112:11112"
|
||||
- "2762:2762"
|
||||
- "2575:2575"
|
||||
- "12575:12575"
|
||||
env_file: docker-compose.env
|
||||
environment:
|
||||
WILDFLY_CHOWN: /opt/wildfly/standalone /storage
|
||||
WILDFLY_WAIT_FOR: ldap:389 db:5432
|
||||
depends_on:
|
||||
- ldap
|
||||
- db
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- ~/dcm4chee-arc/wildfly:/opt/wildfly/standalone
|
||||
- ~/dcm4chee-arc/storage:/storage
|
||||
ohif_viewer:
|
||||
build:
|
||||
# Project root
|
||||
context: ./../../../../
|
||||
# Relative to context
|
||||
dockerfile: ./platform/app/.recipes/Nginx-Dcm4chee/dockerfile
|
||||
image: webapp:latest
|
||||
container_name: ohif_dcm4chee
|
||||
volumes:
|
||||
# Nginx config
|
||||
- ./config/nginx.conf:/etc/nginx/nginx.conf
|
||||
# Logs
|
||||
- ./logs/nginx:/var/logs/nginx
|
||||
# Let's Encrypt
|
||||
# - letsencrypt_certificates:/etc/letsencrypt
|
||||
# - letsencrypt_challenges:/var/www/letsencrypt
|
||||
ports:
|
||||
- '443:443' # SSL
|
||||
- '80:80' # Web
|
||||
restart: on-failure
|
||||
43
platform/app/.recipes/Nginx-Dcm4chee/dockerfile
Normal file
43
platform/app/.recipes/Nginx-Dcm4chee/dockerfile
Normal file
@@ -0,0 +1,43 @@
|
||||
# Stage 1: Build the application
|
||||
FROM node:20.18.1-slim as builder
|
||||
|
||||
# Setup the working directory
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install dependencies
|
||||
# apt-get update is combined with apt-get install to avoid using outdated packages
|
||||
RUN apt-get update && apt-get install -y build-essential python3
|
||||
|
||||
# Copy package.json and other dependency-related files first
|
||||
# Assuming your package.json and yarn.lock or similar are located in the project root
|
||||
|
||||
COPY ./ /usr/src/app/
|
||||
|
||||
# Install node dependencies
|
||||
RUN yarn config set workspaces-experimental true
|
||||
RUN yarn install
|
||||
|
||||
# Copy the rest of the application code
|
||||
|
||||
# set QUICK_BUILD to true to make the build faster for dev
|
||||
ENV APP_CONFIG=config/docker-nginx-dcm4chee.js
|
||||
|
||||
# Build the application
|
||||
RUN yarn run build
|
||||
|
||||
# # Stage 2: Bundle the built application into a Docker container which runs NGINX using Alpine Linux
|
||||
FROM nginx:alpine
|
||||
|
||||
# # Create directories for logs and html content if they don't already exist
|
||||
RUN mkdir -p /var/log/nginx /var/www/html
|
||||
|
||||
|
||||
# # Copy build output to serve static files
|
||||
COPY --from=builder /usr/src/app/platform/app/dist /var/www/html
|
||||
|
||||
# # Expose HTTP and HTTPS ports
|
||||
EXPOSE 80 443
|
||||
|
||||
# # Start NGINX
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
0
platform/app/.recipes/Nginx-Dcm4chee/etc/localtime
Normal file
0
platform/app/.recipes/Nginx-Dcm4chee/etc/localtime
Normal file
1
platform/app/.recipes/Nginx-Dcm4chee/etc/timezone
Normal file
1
platform/app/.recipes/Nginx-Dcm4chee/etc/timezone
Normal file
@@ -0,0 +1 @@
|
||||
America/New_York
|
||||
6
platform/app/.recipes/Nginx-Orthanc-Keycloak/.gitignore
vendored
Normal file
6
platform/app/.recipes/Nginx-Orthanc-Keycloak/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
logs/*
|
||||
volumes/*
|
||||
config/letsencrypt/*
|
||||
config/certbot/*
|
||||
!config/letsencrypt/.gitkeep
|
||||
!config/certbot/.gitkeep
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Start oauth2-proxy
|
||||
oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg &
|
||||
|
||||
# Start nginx
|
||||
nginx -g "daemon off;"
|
||||
208
platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf
Normal file
208
platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf
Normal file
@@ -0,0 +1,208 @@
|
||||
worker_processes 2;
|
||||
error_log /var/logs/nginx/mydomain.error.log;
|
||||
pid /var/run/nginx.pid;
|
||||
include /usr/share/nginx/modules/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include '/etc/nginx/mime.types';
|
||||
default_type application/octet-stream;
|
||||
|
||||
keepalive_timeout 65;
|
||||
keepalive_requests 100000;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
proxy_buffers 16 16k;
|
||||
proxy_buffer_size 32k;
|
||||
proxy_busy_buffers_size 64k;
|
||||
proxy_max_temp_file_size 128k;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name YOUR_DOMAIN;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name YOUR_DOMAIN;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/ohifviewer.duckdns.org/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/ohifviewer.duckdns.org/privkey.pem;
|
||||
|
||||
root /var/www/html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||
gzip_comp_level 9;
|
||||
etag on;
|
||||
|
||||
location /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
proxy_cache_bypass $http_pragma;
|
||||
proxy_cache_revalidate on;
|
||||
expires off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location /oauth2 {
|
||||
expires -1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Auth-Request-Redirect $request_uri;
|
||||
proxy_pass http://localhost:4180$uri$is_args$args;
|
||||
}
|
||||
|
||||
location /oauth2/callback {
|
||||
proxy_pass http://localhost:4180;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /oauth2/sign_out {
|
||||
expires -1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Auth-Request-Redirect /oauth2/sign_in;
|
||||
proxy_pass http://localhost:4180;
|
||||
}
|
||||
|
||||
location /pacs-admin/ {
|
||||
error_page 401 = /oauth2/sign_in?rd=$scheme://$host$request_uri;
|
||||
auth_request /oauth2/auth?allowed_groups=pacsadmin;
|
||||
|
||||
auth_request_set $user $upstream_http_x_auth_request_user;
|
||||
auth_request_set $token $upstream_http_x_auth_request_access_token;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
|
||||
proxy_set_header X-User $user;
|
||||
proxy_set_header X-Access-Token $token;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept' always;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
proxy_pass http://orthanc:8042/;
|
||||
}
|
||||
|
||||
location /pacs-admin {
|
||||
return 301 /pacs-admin/;
|
||||
}
|
||||
|
||||
location /pacs/ {
|
||||
auth_request /oauth2/auth;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept' always;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
proxy_pass http://orthanc:8042/dicom-web/;
|
||||
}
|
||||
|
||||
location /pacs {
|
||||
return 301 /pacs/;
|
||||
}
|
||||
|
||||
location /ohif-viewer/ {
|
||||
expires -1;
|
||||
error_page 401 = /oauth2/sign_in?rd=$scheme://$host$request_uri;
|
||||
auth_request /oauth2/auth;
|
||||
|
||||
auth_request_set $user $upstream_http_x_auth_request_user;
|
||||
auth_request_set $token $upstream_http_x_auth_request_access_token;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
|
||||
proxy_set_header X-User $user;
|
||||
proxy_set_header X-Access-Token $token;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Server $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /ohif-viewer {
|
||||
return 301 /ohif-viewer/;
|
||||
}
|
||||
|
||||
location = / {
|
||||
return 301 /ohif-viewer/;
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
location /keycloak/ {
|
||||
proxy_pass http://keycloak:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /keycloak {
|
||||
return 301 /keycloak/;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
http_address="0.0.0.0:4180"
|
||||
cookie_secret="GENERATEACOOKIESECRET----------------------="
|
||||
email_domains=["*"]
|
||||
cookie_secure="false"
|
||||
cookie_expire="9m30s"
|
||||
cookie_refresh="5m"
|
||||
client_secret="2Xtlde7aozdkzzYHdIxQNfPDr0wNPTgg"
|
||||
client_id="ohif_viewer"
|
||||
redirect_url="http://YOUR_DOMAIN/oauth2/callback"
|
||||
|
||||
ssl_insecure_skip_verify = true
|
||||
insecure_oidc_allow_unverified_email = true
|
||||
pass_access_token = true
|
||||
provider="keycloak-oidc"
|
||||
provider_display_name="Keycloak"
|
||||
user_id_claim="oid"
|
||||
oidc_email_claim="sub"
|
||||
scope="openid"
|
||||
pass_host_header=true
|
||||
code_challenge_method="S256"
|
||||
oidc_issuer_url="http://YOUR_DOMAIN/keycloak/realms/ohif"
|
||||
insecure_oidc_skip_issuer_verification = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"Name": "Orthanc inside Docker",
|
||||
"StorageDirectory": "/var/lib/orthanc/db",
|
||||
"IndexDirectory": "/var/lib/orthanc/db",
|
||||
"StorageCompression": false,
|
||||
"MaximumStorageSize": 0,
|
||||
"MaximumPatientCount": 0,
|
||||
"LuaScripts": [],
|
||||
"Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
|
||||
"ConcurrentJobs": 2,
|
||||
"HttpServerEnabled": true,
|
||||
"HttpPort": 8042,
|
||||
"HttpDescribeErrors": true,
|
||||
"HttpCompressionEnabled": true,
|
||||
"DicomServerEnabled": true,
|
||||
"DicomAet": "ORTHANC",
|
||||
"DicomCheckCalledAet": false,
|
||||
"DicomPort": 4242,
|
||||
"DefaultEncoding": "Latin1",
|
||||
"DeflatedTransferSyntaxAccepted": true,
|
||||
"JpegTransferSyntaxAccepted": true,
|
||||
"Jpeg2000TransferSyntaxAccepted": true,
|
||||
"JpegLosslessTransferSyntaxAccepted": true,
|
||||
"JpipTransferSyntaxAccepted": true,
|
||||
"Mpeg2TransferSyntaxAccepted": true,
|
||||
"RleTransferSyntaxAccepted": true,
|
||||
"UnknownSopClassAccepted": false,
|
||||
"DicomScpTimeout": 30,
|
||||
|
||||
"RemoteAccessAllowed": true,
|
||||
"SslEnabled": false,
|
||||
"SslCertificate": "certificate.pem",
|
||||
"AuthenticationEnabled": false,
|
||||
"RegisteredUsers": {
|
||||
"test": "test"
|
||||
},
|
||||
"DicomModalities": {},
|
||||
"DicomModalitiesInDatabase": false,
|
||||
"DicomAlwaysAllowEcho": true,
|
||||
"DicomAlwaysAllowStore": true,
|
||||
"DicomCheckModalityHost": false,
|
||||
"DicomScuTimeout": 10,
|
||||
"OrthancPeers": {},
|
||||
"OrthancPeersInDatabase": false,
|
||||
"HttpProxy": "",
|
||||
|
||||
"HttpVerbose": true,
|
||||
|
||||
"HttpTimeout": 10,
|
||||
"HttpsVerifyPeers": true,
|
||||
"HttpsCACertificates": "",
|
||||
"UserMetadata": {},
|
||||
"UserContentType": {},
|
||||
"StableAge": 60,
|
||||
"StrictAetComparison": false,
|
||||
"StoreMD5ForAttachments": true,
|
||||
"LimitFindResults": 0,
|
||||
"LimitFindInstances": 0,
|
||||
"LimitJobs": 10,
|
||||
"LogExportedResources": false,
|
||||
"KeepAlive": true,
|
||||
"TcpNoDelay": true,
|
||||
"HttpThreadsCount": 50,
|
||||
"StoreDicom": true,
|
||||
"DicomAssociationCloseDelay": 5,
|
||||
"QueryRetrieveSize": 10,
|
||||
"CaseSensitivePN": false,
|
||||
"LoadPrivateDictionary": true,
|
||||
"Dictionary": {},
|
||||
"SynchronousCMove": true,
|
||||
"JobsHistorySize": 10,
|
||||
"SaveJobs": true,
|
||||
"OverwriteInstances": false,
|
||||
"MediaArchiveSize": 1,
|
||||
"StorageAccessOnFind": "Always",
|
||||
"MetricsEnabled": true,
|
||||
|
||||
"DicomWeb": {
|
||||
"Enable": true,
|
||||
"Root": "/dicom-web/",
|
||||
"EnableWado": true,
|
||||
"WadoRoot": "/wado",
|
||||
"Host": "127.0.0.1",
|
||||
"Ssl": false,
|
||||
"StowMaxInstances": 10,
|
||||
"StowMaxSize": 10,
|
||||
"QidoCaseSensitive": false
|
||||
}
|
||||
}
|
||||
126
platform/app/.recipes/Nginx-Orthanc-Keycloak/docker-compose.yml
Normal file
126
platform/app/.recipes/Nginx-Orthanc-Keycloak/docker-compose.yml
Normal file
@@ -0,0 +1,126 @@
|
||||
services:
|
||||
ohif_viewer:
|
||||
build:
|
||||
context: ./../../../../
|
||||
dockerfile: ./platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile
|
||||
image: webapp:latest
|
||||
container_name: webapp
|
||||
ports:
|
||||
- '443:443' # SSL
|
||||
- '80:80' # Web
|
||||
depends_on:
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
restart: on-failure
|
||||
networks:
|
||||
- default
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
environment:
|
||||
- OAUTH2_PROXY_SKIP_PROVIDER_BUTTON=true
|
||||
volumes:
|
||||
# - ../../app/dist /var/www/html
|
||||
- ./config/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./config/oauth2-proxy.cfg:/etc/oauth2-proxy/oauth2-proxy.cfg
|
||||
|
||||
- ./config/letsencrypt:/etc/letsencrypt
|
||||
- ./config/certbot:/var/www/certbot
|
||||
|
||||
orthanc:
|
||||
image: jodogne/orthanc-plugins
|
||||
hostname: orthanc
|
||||
container_name: orthanc
|
||||
volumes:
|
||||
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
|
||||
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:24.0.5
|
||||
command: 'start-dev --import-realm'
|
||||
hostname: keycloak
|
||||
container_name: keycloak
|
||||
volumes:
|
||||
- ./config/ohif-keycloak-realm.json:/opt/keycloak/data/import/ohif-keycloak-realm.json
|
||||
environment:
|
||||
# Database
|
||||
KC_DB_URL_HOST: postgres
|
||||
KC_DB: postgres
|
||||
KC_DB_URL: 'jdbc:postgresql://postgres:5432/keycloak'
|
||||
KC_DB_SCHEMA: public
|
||||
KC_DB_USERNAME: keycloak
|
||||
KC_DB_PASSWORD: password
|
||||
KC_HOSTNAME_ADMIN_URL: http://YOUR_DOMAIN/keycloak/
|
||||
KC_HOSTNAME_URL: http://YOUR_DOMAIN/keycloak/
|
||||
KC_HOSTNAME_STRICT_BACKCHANNEL: true
|
||||
KC_HOSTNAME_STRICT_HTTPS: false
|
||||
KC_HTTP_ENABLED: true
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: admin
|
||||
KC_HEALTH_ENABLED: true
|
||||
KC_METRICS_ENABLED: true
|
||||
KC_PROXY: edge
|
||||
KC_PROXY_HEADERS: xforwarded
|
||||
KEYCLOAK_JDBC_PARAMS: connectTimeout=40000
|
||||
KC_LOG_LEVEL: INFO
|
||||
KC_HOSTNAME_DEBUG: true
|
||||
# added later
|
||||
PROXY_ADDRESS_FORWARDING: true
|
||||
ports:
|
||||
- 8080:8080
|
||||
depends_on:
|
||||
- postgres
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
healthcheck:
|
||||
test: [
|
||||
'CMD-SHELL',
|
||||
"exec 3<>/dev/tcp/YOUR_DOMAIN/8080;echo -e \"GET /health/ready HTTP/1.1\r
|
||||
|
||||
host: http://localhost\r
|
||||
|
||||
Connection: close\r
|
||||
|
||||
\r
|
||||
|
||||
\" >&3;grep \"HTTP/1.1 200 OK\" <&3",
|
||||
]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
hostname: postgres
|
||||
container_name: postgres
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: keycloak
|
||||
POSTGRES_USER: keycloak
|
||||
POSTGRES_PASSWORD: password
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- default
|
||||
|
||||
certbot:
|
||||
image: certbot/certbot
|
||||
container_name: certbot
|
||||
volumes:
|
||||
- ./config/letsencrypt:/etc/letsencrypt
|
||||
- ./config/certbot:/var/www/certbot
|
||||
entrypoint:
|
||||
/bin/sh -c "trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;"
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
57
platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile
Normal file
57
platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile
Normal file
@@ -0,0 +1,57 @@
|
||||
# Stage 1: Build the application
|
||||
FROM node:20.18.1-slim as builder
|
||||
|
||||
# Setup the working directory
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install dependencies
|
||||
# apt-get update is combined with apt-get install to avoid using outdated packages
|
||||
RUN apt-get update && apt-get install -y build-essential python3
|
||||
|
||||
# Copy package.json and other dependency-related files first
|
||||
# Assuming your package.json and yarn.lock or similar are located in the project root
|
||||
# Todo: this probably can get improved by copying
|
||||
# only the package json files and running yarn install before
|
||||
# copying the rest of the files but having a monorepo setup
|
||||
# makes this a bit more complicated, i wasn't able to get it working
|
||||
COPY ./ /usr/src/app/
|
||||
|
||||
# Install node dependencies
|
||||
RUN yarn config set workspaces-experimental true
|
||||
RUN yarn install
|
||||
|
||||
# Copy the rest of the application code
|
||||
|
||||
# set QUICK_BUILD to true to make the build faster for dev
|
||||
ENV APP_CONFIG=config/docker-nginx-orthanc-keycloak.js
|
||||
|
||||
# Build the application
|
||||
RUN yarn run build
|
||||
|
||||
# Use nginx as the base image
|
||||
FROM nginx:alpine
|
||||
|
||||
# Install dependencies for oauth2-proxy
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p /var/logs/nginx /var/www/html /etc/oauth2-proxy
|
||||
|
||||
# Download and install oauth2-proxy
|
||||
RUN curl -L https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.4.0/oauth2-proxy-v7.4.0.linux-amd64.tar.gz -o oauth2-proxy.tar.gz && \
|
||||
tar -xvzf oauth2-proxy.tar.gz && \
|
||||
mv oauth2-proxy-v7.4.0.linux-amd64/oauth2-proxy /usr/local/bin/ && \
|
||||
rm -rf oauth2-proxy-v7.4.0.linux-amd64 oauth2-proxy.tar.gz
|
||||
|
||||
|
||||
COPY --from=builder /usr/src/app/platform/app/dist /var/www/html
|
||||
|
||||
# Copy the entrypoint script
|
||||
COPY ./platform/app/.recipes/Nginx-Orthanc-Keycloak/config/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Expose necessary ports
|
||||
EXPOSE 80 443 4180
|
||||
# Set the entrypoint script as the entrypoint
|
||||
RUN chmod +x entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
2
platform/app/.recipes/Nginx-Orthanc/.gitignore
vendored
Normal file
2
platform/app/.recipes/Nginx-Orthanc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
logs/*
|
||||
volumes/*
|
||||
26
platform/app/.recipes/Nginx-Orthanc/README.md
Normal file
26
platform/app/.recipes/Nginx-Orthanc/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Docker compose files
|
||||
|
||||
# Build
|
||||
|
||||
Using docker compose you can build the image with the following command:
|
||||
|
||||
```bash
|
||||
docker-compose build
|
||||
```
|
||||
|
||||
# Run
|
||||
|
||||
To run the container use the following command:
|
||||
|
||||
```bash
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
|
||||
# Routes
|
||||
|
||||
http://localhost/ -> OHIF
|
||||
localhost/pacs -> Orthanc
|
||||
|
||||
|
||||
See [here](../../../docs/docs/deployment/nginx--image-archive.md) for more information about this recipe.
|
||||
85
platform/app/.recipes/Nginx-Orthanc/config/nginx.conf
Normal file
85
platform/app/.recipes/Nginx-Orthanc/config/nginx.conf
Normal file
@@ -0,0 +1,85 @@
|
||||
worker_processes 2;
|
||||
error_log /var/logs/nginx/mydomain.error.log;
|
||||
pid /var/run/nginx.pid;
|
||||
include /usr/share/nginx/modules/*.conf; # See /usr/share/doc/nginx/README.dynamic.
|
||||
|
||||
events {
|
||||
worker_connections 1024; ## Default: 1024
|
||||
use epoll; # http://nginx.org/en/docs/events.html
|
||||
multi_accept on; # http://nginx.org/en/docs/ngx_core_module.html#multi_accept
|
||||
}
|
||||
|
||||
# Core Modules Docs:
|
||||
# http://nginx.org/en/docs/http/ngx_http_core_module.html
|
||||
http {
|
||||
include '/etc/nginx/mime.types';
|
||||
default_type application/octet-stream;
|
||||
|
||||
keepalive_timeout 65;
|
||||
keepalive_requests 100000;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
|
||||
|
||||
# Nginx `listener` block
|
||||
server {
|
||||
listen [::]:80 default_server;
|
||||
listen 80;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||
gzip_comp_level 9;
|
||||
etag on;
|
||||
|
||||
|
||||
# Reverse Proxy for `orthanc` APIs (including DICOMWeb)
|
||||
#
|
||||
location /pacs/ {
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
# Add CORS headers
|
||||
# Note: uncomment the following line to allow all domains to access the Orthanc APIs
|
||||
# You should actually only allow the domains you trust to access the APIs
|
||||
# add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
|
||||
proxy_pass http://orthanc:8042/;
|
||||
|
||||
# By default, this endpoint is protected by CORS (cross-origin-resource-sharing)
|
||||
# You can add headers to allow other domains to request this resource.
|
||||
# See the "Updating CORS Settings" example below
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
}
|
||||
|
||||
|
||||
# Do not cache sw.js, required for offline-first updates.
|
||||
location /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
proxy_cache_bypass $http_pragma;
|
||||
proxy_cache_revalidate on;
|
||||
expires off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
|
||||
# Single Page App
|
||||
# Try files, fallback to index.html
|
||||
#
|
||||
location / {
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
89
platform/app/.recipes/Nginx-Orthanc/config/orthanc.json
Normal file
89
platform/app/.recipes/Nginx-Orthanc/config/orthanc.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"Name": "Orthanc inside Docker",
|
||||
"StorageDirectory": "/var/lib/orthanc/db",
|
||||
"IndexDirectory": "/var/lib/orthanc/db",
|
||||
"StorageCompression": false,
|
||||
"MaximumStorageSize": 0,
|
||||
"MaximumPatientCount": 0,
|
||||
"LuaScripts": [],
|
||||
"Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
|
||||
"ConcurrentJobs": 2,
|
||||
"HttpServerEnabled": true,
|
||||
"HttpPort": 8042,
|
||||
"HttpDescribeErrors": true,
|
||||
"HttpCompressionEnabled": true,
|
||||
"DicomServerEnabled": true,
|
||||
"DicomAet": "ORTHANC",
|
||||
"DicomCheckCalledAet": false,
|
||||
"DicomPort": 4242,
|
||||
"DefaultEncoding": "Latin1",
|
||||
"DeflatedTransferSyntaxAccepted": true,
|
||||
"JpegTransferSyntaxAccepted": true,
|
||||
"Jpeg2000TransferSyntaxAccepted": true,
|
||||
"JpegLosslessTransferSyntaxAccepted": true,
|
||||
"JpipTransferSyntaxAccepted": true,
|
||||
"Mpeg2TransferSyntaxAccepted": true,
|
||||
"RleTransferSyntaxAccepted": true,
|
||||
"UnknownSopClassAccepted": false,
|
||||
"DicomScpTimeout": 30,
|
||||
|
||||
"RemoteAccessAllowed": true,
|
||||
"SslEnabled": false,
|
||||
"SslCertificate": "certificate.pem",
|
||||
"AuthenticationEnabled": false,
|
||||
"RegisteredUsers": {
|
||||
"test": "test"
|
||||
},
|
||||
"DicomModalities": {},
|
||||
"DicomModalitiesInDatabase": false,
|
||||
"DicomAlwaysAllowEcho": true,
|
||||
"DicomAlwaysAllowStore": true,
|
||||
"DicomCheckModalityHost": false,
|
||||
"DicomScuTimeout": 10,
|
||||
"OrthancPeers": {},
|
||||
"OrthancPeersInDatabase": false,
|
||||
"HttpProxy": "",
|
||||
|
||||
"HttpVerbose": true,
|
||||
|
||||
"HttpTimeout": 10,
|
||||
"HttpsVerifyPeers": true,
|
||||
"HttpsCACertificates": "",
|
||||
"UserMetadata": {},
|
||||
"UserContentType": {},
|
||||
"StableAge": 60,
|
||||
"StrictAetComparison": false,
|
||||
"StoreMD5ForAttachments": true,
|
||||
"LimitFindResults": 0,
|
||||
"LimitFindInstances": 0,
|
||||
"LimitJobs": 10,
|
||||
"LogExportedResources": false,
|
||||
"KeepAlive": true,
|
||||
"TcpNoDelay": true,
|
||||
"HttpThreadsCount": 50,
|
||||
"StoreDicom": true,
|
||||
"DicomAssociationCloseDelay": 5,
|
||||
"QueryRetrieveSize": 10,
|
||||
"CaseSensitivePN": false,
|
||||
"LoadPrivateDictionary": true,
|
||||
"Dictionary": {},
|
||||
"SynchronousCMove": true,
|
||||
"JobsHistorySize": 10,
|
||||
"SaveJobs": true,
|
||||
"OverwriteInstances": false,
|
||||
"MediaArchiveSize": 1,
|
||||
"StorageAccessOnFind": "Always",
|
||||
"MetricsEnabled": true,
|
||||
|
||||
"DicomWeb": {
|
||||
"Enable": true,
|
||||
"Root": "/dicom-web/",
|
||||
"EnableWado": true,
|
||||
"WadoRoot": "/wado",
|
||||
"Host": "127.0.0.1",
|
||||
"Ssl": false,
|
||||
"StowMaxInstances": 10,
|
||||
"StowMaxSize": 10,
|
||||
"QidoCaseSensitive": false
|
||||
}
|
||||
}
|
||||
46
platform/app/.recipes/Nginx-Orthanc/docker-compose.yml
Normal file
46
platform/app/.recipes/Nginx-Orthanc/docker-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
# Reference:
|
||||
# - https://docs.docker.com/compose/compose-file
|
||||
# - https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/
|
||||
|
||||
services:
|
||||
# Exposed server that's handling incoming web requests
|
||||
ohif_viewer:
|
||||
build:
|
||||
# Project root
|
||||
context: ./../../../../
|
||||
# Relative to context
|
||||
dockerfile: ./platform/app/.recipes/Nginx-Orthanc/dockerfile
|
||||
image: webapp:latest
|
||||
container_name: ohif_orthanc
|
||||
volumes:
|
||||
# Nginx config
|
||||
- ./config/nginx.conf:/etc/nginx/nginx.conf
|
||||
# Logs
|
||||
- ./logs/nginx:/var/logs/nginx
|
||||
# Let's Encrypt
|
||||
# - letsencrypt_certificates:/etc/letsencrypt
|
||||
# - letsencrypt_challenges:/var/www/letsencrypt
|
||||
ports:
|
||||
- '443:443' # SSL
|
||||
- '80:80' # Web
|
||||
depends_on:
|
||||
# - keycloak
|
||||
- orthanc
|
||||
restart: on-failure
|
||||
|
||||
# LINK: https://hub.docker.com/r/jodogne/orthanc-plugins/
|
||||
# TODO: Update to use Postgres
|
||||
# https://github.com/mrts/docker-postgresql-multiple-databases
|
||||
orthanc:
|
||||
image: jodogne/orthanc-plugins
|
||||
hostname: orthanc
|
||||
container_name: orthancPACS
|
||||
volumes:
|
||||
# Config
|
||||
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
|
||||
# Persist data
|
||||
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '4242:4242' # Orthanc REST API
|
||||
- '8042:8042' # Orthanc HTTP
|
||||
43
platform/app/.recipes/Nginx-Orthanc/dockerfile
Normal file
43
platform/app/.recipes/Nginx-Orthanc/dockerfile
Normal file
@@ -0,0 +1,43 @@
|
||||
# Stage 1: Build the application
|
||||
FROM node:20.18.1-slim as builder
|
||||
|
||||
# Setup the working directory
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install dependencies
|
||||
# apt-get update is combined with apt-get install to avoid using outdated packages
|
||||
RUN apt-get update && apt-get install -y build-essential python3
|
||||
|
||||
# Copy package.json and other dependency-related files first
|
||||
# Assuming your package.json and yarn.lock or similar are located in the project root
|
||||
|
||||
COPY ./ /usr/src/app/
|
||||
|
||||
# Install node dependencies
|
||||
RUN yarn config set workspaces-experimental true
|
||||
RUN yarn install
|
||||
|
||||
# Copy the rest of the application code
|
||||
|
||||
# set QUICK_BUILD to true to make the build faster for dev
|
||||
ENV APP_CONFIG=config/docker-nginx-orthanc.js
|
||||
|
||||
# Build the application
|
||||
RUN yarn run build
|
||||
|
||||
# # Stage 2: Bundle the built application into a Docker container which runs NGINX using Alpine Linux
|
||||
FROM nginx:alpine
|
||||
|
||||
# # Create directories for logs and html content if they don't already exist
|
||||
RUN mkdir -p /var/log/nginx /var/www/html
|
||||
|
||||
|
||||
# # Copy build output to serve static files
|
||||
COPY --from=builder /usr/src/app/platform/app/dist /var/www/html
|
||||
|
||||
# # Expose HTTP and HTTPS ports
|
||||
EXPOSE 80 443
|
||||
|
||||
# # Start NGINX
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
Reference in New Issue
Block a user