From 2e198c62d84b730e4ba4393eea004bdbdce1bca1 Mon Sep 17 00:00:00 2001 From: Phoevos Kalemkeris Date: Tue, 18 Mar 2025 10:01:12 +0000 Subject: [PATCH] proxy: Access CMS instances through subpaths Expose CogStack ModelServe instances (services listening on port 8000) as subpaths through the proxy, alleviating the need to hardcode host port mappings in the client applications. Instead, requests to `/cms/` are forwarded to `:8000` internally using the Docker DNS resolver. This also allows us to access user-deployed CMS instances through the proxy without any configuration changes. The rest of the services included in the stack (e.g. Grafana, MLflow) are still available through their respective host port mappings. Even though efforts were made to integrate them as subpaths, they are not fully supported at this stage. More specifically, while accessing exact paths through their APIs might be possible, accessing their web interfaces when using subpaths is problematic, due to the way these external services handle redirects. Even though we employ certain heuristics to rewrite local URLs we can't account for all possible cases, e.g. local paths in HTML responses. This is a known limitation that should be addressed in future iterations. Signed-off-by: Phoevos Kalemkeris --- docker-compose-proxy.yml | 11 +-- docker/nginx/etc/nginx/nginx.conf | 86 ++++++++++++++++--- .../etc/nginx/sites-enabled/huggingface-ner | 37 -------- .../nginx/etc/nginx/sites-enabled/medcat-deid | 37 -------- .../etc/nginx/sites-enabled/medcat-icd10 | 37 -------- .../etc/nginx/sites-enabled/medcat-snomed | 38 -------- .../nginx/etc/nginx/sites-enabled/medcat-umls | 37 -------- 7 files changed, 79 insertions(+), 204 deletions(-) delete mode 100644 docker/nginx/etc/nginx/sites-enabled/huggingface-ner delete mode 100644 docker/nginx/etc/nginx/sites-enabled/medcat-deid delete mode 100644 docker/nginx/etc/nginx/sites-enabled/medcat-icd10 delete mode 100644 docker/nginx/etc/nginx/sites-enabled/medcat-snomed delete mode 100644 docker/nginx/etc/nginx/sites-enabled/medcat-umls diff --git a/docker-compose-proxy.yml b/docker-compose-proxy.yml index a6faa01..7ee7d53 100644 --- a/docker-compose-proxy.yml +++ b/docker-compose-proxy.yml @@ -23,13 +23,10 @@ services: - http_proxy=$HTTP_PROXY - https_proxy=$HTTPS_PROXY - no_proxy=localhost + expose: + - 443 ports: - - 28180:28180 # medcat-snomed - - 28181:28181 # medcat-icd10 -# - 28182:28182 # de-identification (deprecated) - - 28183:28183 # medcat-deid (anoncat) - - 28184:28184 # medcat-umls - - 28185:28185 # huggingface-ner + - 443:443 # cms - 28199:28199 # minio - 28200:28200 # mlflow-ui - 28201:28201 # prometheus @@ -43,4 +40,4 @@ services: networks: cogstack-model-serve_cms: - external: true \ No newline at end of file + external: true diff --git a/docker/nginx/etc/nginx/nginx.conf b/docker/nginx/etc/nginx/nginx.conf index c99940e..edca441 100644 --- a/docker/nginx/etc/nginx/nginx.conf +++ b/docker/nginx/etc/nginx/nginx.conf @@ -16,21 +16,85 @@ http { client_max_body_size 500M; server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name localhost; + + add_header Strict-Transport-Security "max-age=31536000" always; + + ssl_session_cache shared:SSL:20m; + ssl_session_timeout 10m; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; + ssl_stapling on; + ssl_stapling_verify on; + + resolver 8.8.8.8 8.8.4.4; + + ssl_certificate /etc/nginx/root-ca.pem; + ssl_certificate_key /etc/nginx/root-ca.key; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + location /health { include cors.conf; access_log off; return 200 "OK\n"; } + + location ~ ^/cms/(?[^/]+)(?/.*)?$ { + include cors.conf; + resolver 127.0.0.11 valid=30s; + set $upstream $service:8000; + + # FIXME: Access web interfaces (e.g. Grafana, MLflow) through subpaths on the proxy. + # The following services only work when accessed directly through their respective APIs. + # Attempting to access their UI through the proxy leads to issues due to the way they + # handle redirects (even though we can employ certain heuristics to rewrite local URLs + # we can't account for all possible cases, e.g. local paths in HTML responses). As a + # result, accessing these web intercases through the proxy is only possible using the + # available host port mappings instead of the subpaths under /cms for the time being. + if ($service = "grafana") { + set $upstream $service:3000; + } + + if ($service = "graylog") { + set $upstream $service:9000; + } + + if ($service = "minio") { + set $upstream $service:9001; + } + + if ($service = "mlflow-ui") { + set $upstream $service:5000; + } + + if ($service = "prometheus") { + set $upstream $service:9090; + } + + proxy_pass http://$upstream$subpath; + + proxy_redirect http://$upstream$subpath $scheme://$host/cms/$service$subpath; + proxy_redirect http://$upstream/ $scheme://$host/cms/$service/; + proxy_redirect http://$upstream $scheme://$host/cms/$service; + proxy_redirect / $scheme://$host/cms/$service/; + + 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; + + error_page 502 503 504 = @fallback; + } + + location @fallback { + return 503 "Service is temporarily unavailable. Please try again later."; + } } - include sites-enabled/medcat-snomed; - include sites-enabled/medcat-icd10; - include sites-enabled/medcat-deid; - include sites-enabled/medcat-umls; - include sites-enabled/huggingface-ner; - include sites-enabled/mlflow-ui; - include sites-enabled/minio; - include sites-enabled/prometheus; - include sites-enabled/grafana; - include sites-enabled/graylog; -} \ No newline at end of file + include sites-enabled/*; +} diff --git a/docker/nginx/etc/nginx/sites-enabled/huggingface-ner b/docker/nginx/etc/nginx/sites-enabled/huggingface-ner deleted file mode 100644 index c42ae72..0000000 --- a/docker/nginx/etc/nginx/sites-enabled/huggingface-ner +++ /dev/null @@ -1,37 +0,0 @@ -server { - listen 28185 ssl http2 default_server; - listen [::]:28185 ssl http2 default_server; - server_name localhost; - - add_header Strict-Transport-Security "max-age=31536000" always; - - ssl_session_cache shared:SSL:20m; - ssl_session_timeout 10m; - - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; - - ssl_stapling on; - ssl_stapling_verify on; - resolver 8.8.8.8 8.8.4.4; - - ssl_certificate /etc/nginx/root-ca.pem; - ssl_certificate_key /etc/nginx/root-ca.key; - - access_log /var/log/nginx/access_huggingface-ner.log; - error_log /var/log/nginx/error_huggingface-ner.log; - - location / { - include cors.conf; - resolver 127.0.0.11 valid=30s; - set $backend "huggingface-ner:8000"; - proxy_pass http://$backend; - proxy_set_header Host $host; - error_page 502 503 504 = @fallback; - } - - location @fallback { - return 503 "Service is temporarily unavailable. Please try again later."; - } -} \ No newline at end of file diff --git a/docker/nginx/etc/nginx/sites-enabled/medcat-deid b/docker/nginx/etc/nginx/sites-enabled/medcat-deid deleted file mode 100644 index 781142c..0000000 --- a/docker/nginx/etc/nginx/sites-enabled/medcat-deid +++ /dev/null @@ -1,37 +0,0 @@ -server { - listen 28183 ssl http2 default_server; - listen [::]:28183 ssl http2 default_server; - server_name localhost; - - add_header Strict-Transport-Security "max-age=31536000" always; - - ssl_session_cache shared:SSL:20m; - ssl_session_timeout 10m; - - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; - - ssl_stapling on; - ssl_stapling_verify on; - resolver 8.8.8.8 8.8.4.4; - - ssl_certificate /etc/nginx/root-ca.pem; - ssl_certificate_key /etc/nginx/root-ca.key; - - access_log /var/log/nginx/access_medcat-deid.log; - error_log /var/log/nginx/error_medcat-deid.log; - - location / { - include cors.conf; - resolver 127.0.0.11 valid=30s; - set $backend "medcat-deid:8000"; - proxy_pass http://$backend; - proxy_set_header Host $host; - error_page 502 503 504 = @fallback; - } - - location @fallback { - return 503 "Service is temporarily unavailable. Please try again later."; - } -} \ No newline at end of file diff --git a/docker/nginx/etc/nginx/sites-enabled/medcat-icd10 b/docker/nginx/etc/nginx/sites-enabled/medcat-icd10 deleted file mode 100644 index 675301d..0000000 --- a/docker/nginx/etc/nginx/sites-enabled/medcat-icd10 +++ /dev/null @@ -1,37 +0,0 @@ -server { - listen 28181 ssl http2 default_server; - listen [::]:28181 ssl http2 default_server; - server_name localhost; - - add_header Strict-Transport-Security "max-age=31536000" always; - - ssl_session_cache shared:SSL:20m; - ssl_session_timeout 10m; - - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; - - ssl_stapling on; - ssl_stapling_verify on; - resolver 8.8.8.8 8.8.4.4; - - ssl_certificate /etc/nginx/root-ca.pem; - ssl_certificate_key /etc/nginx/root-ca.key; - - access_log /var/log/nginx/access_medcat-icd10.log; - error_log /var/log/nginx/error_medcat-icd10.log; - - location / { - include cors.conf; - resolver 127.0.0.11 valid=30s; - set $backend "medcat-icd10:8000"; - proxy_pass http://$backend; - proxy_set_header Host $host; - error_page 502 503 504 = @fallback; - } - - location @fallback { - return 503 "Service is temporarily unavailable. Please try again later."; - } -} \ No newline at end of file diff --git a/docker/nginx/etc/nginx/sites-enabled/medcat-snomed b/docker/nginx/etc/nginx/sites-enabled/medcat-snomed deleted file mode 100644 index bd78d21..0000000 --- a/docker/nginx/etc/nginx/sites-enabled/medcat-snomed +++ /dev/null @@ -1,38 +0,0 @@ -server { - listen 28180 ssl http2 default_server; - listen [::]:28180 ssl http2 default_server; - server_name localhost; - - add_header Strict-Transport-Security "max-age=31536000" always; - - ssl_session_cache shared:SSL:20m; - ssl_session_timeout 10m; - - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; - - ssl_stapling on; - ssl_stapling_verify on; - resolver 8.8.8.8 8.8.4.4; - - ssl_certificate /etc/nginx/root-ca.pem; - ssl_certificate_key /etc/nginx/root-ca.key; - - access_log /var/log/nginx/access_medcat-snomed.log; - error_log /var/log/nginx/error_medcat-snomed.log; - - location / { - include cors.conf; - resolver 127.0.0.11 valid=30s; - set $backend "medcat-snomed:8000"; - proxy_pass http://$backend; - proxy_set_header Host $host; - error_page 502 503 504 = @fallback; - } - - location @fallback { - return 503 "Service is temporarily unavailable. Please try again later."; - } - -} \ No newline at end of file diff --git a/docker/nginx/etc/nginx/sites-enabled/medcat-umls b/docker/nginx/etc/nginx/sites-enabled/medcat-umls deleted file mode 100644 index 2e5e3d8..0000000 --- a/docker/nginx/etc/nginx/sites-enabled/medcat-umls +++ /dev/null @@ -1,37 +0,0 @@ -server { - listen 28184 ssl http2 default_server; - listen [::]:28184 ssl http2 default_server; - server_name localhost; - - add_header Strict-Transport-Security "max-age=31536000" always; - - ssl_session_cache shared:SSL:20m; - ssl_session_timeout 10m; - - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;"; - - ssl_stapling on; - ssl_stapling_verify on; - resolver 8.8.8.8 8.8.4.4; - - ssl_certificate /etc/nginx/root-ca.pem; - ssl_certificate_key /etc/nginx/root-ca.key; - - access_log /var/log/nginx/access_medcat-umls.log; - error_log /var/log/nginx/error_medcat-umls.log; - - location / { - include cors.conf; - resolver 127.0.0.11 valid=30s; - set $backend "medcat-umls:8000"; - proxy_pass http://$backend; - proxy_set_header Host $host; - error_page 502 503 504 = @fallback; - } - - location @fallback { - return 503 "Service is temporarily unavailable. Please try again later."; - } -} \ No newline at end of file