Created
May 18, 2026 05:37
-
-
Save swerder/5eea4267cb116adbbb7565e2f7a95a7c to your computer and use it in GitHub Desktop.
zskarte nginx config to wrap password protected wms source incl caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| set -e | |
| if [ -z "${WMS_SECURE_DOMAIN}" ]; then | |
| echo "ERROR: WMS_SECURE_DOMAIN is required" | |
| exit 1 | |
| fi | |
| export LOGIN_COMMENTED="" | |
| if [ "${WMS_NO_LOGIN}" = "1" ]; then | |
| export LOGIN_COMMENTED="#" | |
| if [ "${WMS_CACHE_DISABLED}" = "1" ]; then | |
| echo "ERROR: WMS_NO_LOGIN=1 and cache disabled (WMS_CACHE_DISABLED=1) does not make sense, in this case use it directly." | |
| exit 2 | |
| fi | |
| elif [ -n "${WMS_BASIC_USER}" ] && [ -n "${WMS_BASIC_PASS}" ]; then | |
| export WMS_AUTH_HEADER="Basic $(printf '%s' "${WMS_BASIC_USER}:${WMS_BASIC_PASS}" | base64 | tr -d '\n')" | |
| elif [ -n "${WMS_JWT_TOKEN}" ]; then | |
| export WMS_AUTH_HEADER="Bearer ${WMS_JWT_TOKEN}" | |
| elif [ "${WMS_OFFLINE_MODE}" = "0" ]; then | |
| echo "ERROR: WMS_BASIC_USER and WMS_BASIC_PASS or an valid WMS_JWT_TOKEN is required" | |
| exit 3 | |
| elif [ "${WMS_OFFLINE_MODE}" = "1" ] && [ "${WMS_CACHE_DISABLED}" = "1" ]; then | |
| echo "ERROR: WMS_OFFLINE_MODE=1 and WMS_CACHE_DISABLED=1 does not make sense, nothing to server than." | |
| exit 4 | |
| fi | |
| if [ "${WMS_CACHE_DISABLED}" = "1" ]; then | |
| export CACHE_COMMENTED="#" | |
| else | |
| export CACHE_COMMENTED="" | |
| fi | |
| if [ "${WMS_OFFLINE_MODE}" = "1" ]; then | |
| export ONLINE_COMMENTED="" | |
| export OFFLINE_COMMENTED="#" | |
| else | |
| export ONLINE_COMMENTED="#" | |
| export OFFLINE_COMMENTED="" | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # define cache dir, keep unused/stale cache 400d | |
| ${CACHE_COMMENTED}proxy_cache_path /var/cache/nginx/wms_cache levels=1:2 keys_zone=wms_cache:20m max_size=1g inactive=400d use_temp_path=off; | |
| server { | |
| listen 80; | |
| server_name localhost; | |
| # Cache Keys based on URL with query params | |
| ${CACHE_COMMENTED}proxy_cache_key "$request_uri"; | |
| ${CACHE_COMMENTED}proxy_cache wms_cache; | |
| # cache validation | |
| ${CACHE_COMMENTED}proxy_ignore_headers Cache-Control Expires Set-Cookie Vary; | |
| ${CACHE_COMMENTED}proxy_cache_valid 200 302 ${WMS_CACHE_DURATION}; # Cache 30 day on success | |
| ${CACHE_COMMENTED}proxy_cache_valid 404 1m; # 404 only 1 min | |
| ${CACHE_COMMENTED}proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; | |
| ${CACHE_COMMENTED}proxy_cache_revalidate off; # revalidate (by if-modified request) does not make sense, as WMS always return modified | |
| location / { | |
| set $cors_origin $http_origin; | |
| # Cache bypass for OPTIONS requests | |
| set $skip_cache 0; | |
| if ($request_method = 'OPTIONS') { | |
| set $skip_cache 1; | |
| } | |
| ${CACHE_COMMENTED}proxy_cache_bypass $skip_cache; | |
| ${CACHE_COMMENTED}proxy_cache_lock on; | |
| # 1. OPTIONS handling | |
| if ($request_method = 'OPTIONS') { | |
| add_header 'Access-Control-Allow-Origin' $cors_origin always; | |
| add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always; | |
| add_header 'Access-Control-Allow-Credentials' 'true' always; | |
| add_header 'Access-Control-Max-Age' 1728000 always; | |
| add_header 'Content-Type' 'text/plain; charset=UTF-8' always; | |
| add_header 'Content-Length' 0 always; | |
| return 204; | |
| } | |
| # 2. first set own CORS-Header | |
| add_header 'Access-Control-Allow-Origin' $cors_origin always; | |
| add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always; | |
| add_header 'Access-Control-Allow-Credentials' 'true' always; | |
| # 3. XML Substitution (return wrapper url inside capabilities xml) | |
| proxy_set_header Accept-Encoding ""; | |
| sub_filter_once off; | |
| sub_filter_types text/xml application/xml; | |
| sub_filter 'http://${WMS_SECURE_DOMAIN}' '$scheme://$host:${WMS_WRAPPER_PORT}'; | |
| sub_filter 'https://${WMS_SECURE_DOMAIN}' '$scheme://$host:${WMS_WRAPPER_PORT}'; | |
| sub_filter '${WMS_SECURE_DOMAIN}' '$host:${WMS_WRAPPER_PORT}'; | |
| # 4. Proxy | |
| ${CACHE_COMMENTED}proxy_ignore_client_abort on; # continue handling also if client abort | |
| ${OFFLINE_COMMENTED}proxy_connect_timeout 5s; | |
| ${OFFLINE_COMMENTED}proxy_send_timeout 30s; | |
| ${OFFLINE_COMMENTED}proxy_read_timeout 30s; | |
| ${OFFLINE_COMMENTED}proxy_pass https://${WMS_SECURE_DOMAIN}; | |
| ${ONLINE_COMMENTED}proxy_connect_timeout 1s; | |
| ${ONLINE_COMMENTED}proxy_send_timeout 1s; | |
| ${ONLINE_COMMENTED}proxy_read_timeout 1s; | |
| ${ONLINE_COMMENTED}proxy_pass http://127.0.0.1:9999; # fake endpoint directly fail | |
| proxy_set_header Host ${WMS_SECURE_DOMAIN}; | |
| 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; | |
| ${LOGIN_COMMENTED}proxy_set_header Authorization '${WMS_AUTH_HEADER}'; | |
| proxy_ssl_server_name on; | |
| # 5. remove remote CORS-Header (after proxy_pass) | |
| proxy_hide_header 'Access-Control-Allow-Origin'; | |
| proxy_hide_header 'Access-Control-Allow-Methods'; | |
| proxy_hide_header 'Access-Control-Allow-Headers'; | |
| proxy_hide_header 'Access-Control-Allow-Credentials'; | |
| proxy_hide_header 'Access-Control-Max-Age'; | |
| proxy_hide_header 'Access-Control-Expose-Headers'; | |
| # 6. remove Cache Header from upstream | |
| proxy_hide_header 'Cache-Control'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Pragma'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Expires'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Age'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Vary'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'X-Cache'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'X-Varnish'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Set-Cookie'; | |
| ${CACHE_COMMENTED}proxy_hide_header 'Last-Modified'; | |
| # 7. add Cache Header | |
| add_header Cache-Control "public, max-age=86400" always; # 1 day | |
| ${CACHE_COMMENTED}add_header X-Cache-Status $upstream_cache_status always; | |
| ${CACHE_COMMENTED}add_header Last-Modified $upstream_http_date always; # use WMS/Cache date as Last-Modified | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| version: '3.8' | |
| services: | |
| wms-wrapper: | |
| image: nginx:alpine | |
| ports: | |
| - "${WMS_WRAPPER_PORT:-4400}:80" | |
| volumes: | |
| - ./nginx.conf:/etc/nginx/nginx.conf:ro | |
| - ./default.conf.template:/etc/nginx/templates/default.conf.template:ro | |
| - ./10-prepare-env.sh:/docker-entrypoint.d/10-prepare-env.envsh | |
| - ./cache:/var/cache/nginx/wms_cache | |
| environment: | |
| - WMS_SECURE_DOMAIN=${WMS_SECURE_DOMAIN:-} | |
| - WMS_WRAPPER_PORT=${WMS_WRAPPER_PORT:-4400} | |
| - WMS_BASIC_USER=${WMS_BASIC_USER:-} | |
| - WMS_BASIC_PASS=${WMS_BASIC_PASS:-} | |
| - WMS_JWT_TOKEN=${WMS_JWT_TOKEN:-} | |
| - WMS_NO_LOGIN=${WMS_NO_LOGIN:-0} | |
| - WMS_CACHE_DISABLED=${WMS_CACHE_DISABLED:-0} | |
| - WMS_CACHE_DURATION=${WMS_CACHE_DURATION:-30d} | |
| - WMS_OFFLINE_MODE=${WMS_OFFLINE_MODE:-0} | |
| restart: unless-stopped |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| user nginx; | |
| worker_processes auto; | |
| error_log /var/log/nginx/error.log notice; | |
| pid /run/nginx.pid; | |
| events { | |
| worker_connections 1024; | |
| } | |
| http { | |
| include /etc/nginx/mime.types; | |
| default_type application/octet-stream; | |
| # add cache info to log | |
| log_format main '$remote_addr - $remote_user [$time_local] "$request" ' | |
| '$status $body_bytes_sent "$http_referer" ' | |
| '"$http_user_agent" "$http_x_forwarded_for"' | |
| 'cache: "$upstream_cache_status"'; | |
| access_log /var/log/nginx/access.log main; | |
| sendfile on; | |
| #tcp_nopush on; | |
| keepalive_timeout 65; | |
| #gzip on; | |
| include /etc/nginx/conf.d/*.conf; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @echo off | |
| set WMS_SECURE_DOMAIN=secure.geowms.my.bl.ch | |
| set WMS_WRAPPER_PORT=4400 | |
| set WMS_BASIC_USER="BL1000XXXX" | |
| set WMS_BASIC_PASS="secretPassword" | |
| ::if jwt is used, define valid token here and renew and restart if required | |
| ::set WMS_JWT_TOKEN=eyJhb..... | |
| ::if no login is required but caching function should be use, set to 1 | |
| set WMS_NO_LOGIN=0 | |
| mkdir cache | |
| set WMS_CACHE_DISABLED=0 | |
| set WMS_CACHE_DURATION=30d | |
| ::to only return already cached content set to 1 | |
| set WMS_OFFLINE_MODE=0 | |
| docker compose up -d | |
| timeout /t 1 >nul | |
| docker compose logs --tail=200 | findstr /i "ERROR" | |
| if %errorlevel%==0 ( | |
| docker compose down | |
| exit 1 | |
| ) | |
| if %WMS_OFFLINE_MODE% == 1 GOTO :EOF | |
| if %WMS_CACHE_DISABLED% == 1 GOTO :EOF | |
| echo INFO: wait to check upstream reachable | |
| timeout /t 5 >nul | |
| docker compose logs --tail=200 | findstr /i "host not found in upstream" | |
| if %errorlevel%==0 ( | |
| echo ERROR: restart in offline mode | |
| set WMS_OFFLINE_MODE=1 | |
| docker compose up -d | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| export WMS_SECURE_DOMAIN=secure.geowms.my.bl.ch | |
| export WMS_WRAPPER_PORT=4400 | |
| export WMS_BASIC_USER="BL1000XXXX" | |
| export WMS_BASIC_PASS="secretPassword" | |
| #if jwt is used, define valid token here and renew and restart if required | |
| #export WMS_JWT_TOKEN=eyJhb..... | |
| #if no login is required but caching function should be use, set to 1 | |
| export WMS_NO_LOGIN=0 | |
| mkdir -p cache | |
| export WMS_CACHE_DISABLED=0 | |
| export WMS_CACHE_DURATION=30d | |
| #to only return already cached content set to 1 | |
| export WMS_OFFLINE_MODE=0 | |
| docker compose up -d | |
| sleep 1 | |
| if docker compose logs --tail=200 | grep "ERROR"; then | |
| docker compose down | |
| exit 1 | |
| fi | |
| ([ ${WMS_OFFLINE_MODE} == 1 ] || [ ${WMS_CACHE_DISABLED} == 1 ]) && exit | |
| echo "INFO: wait to check upstream reachable" | |
| sleep 5 | |
| if docker compose logs --tail=200 | grep "host not found in upstream"; then | |
| echo "ERROR: restart in offline mode" >&2 | |
| export WMS_OFFLINE_MODE=1 | |
| docker compose up -d | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @echo off | |
| docker compose down |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| docker compose down |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The files in this gist can be used to access password protected WMS sources from zskarte.ch
You need to have docker installed, adjust the credentials in the start script and run it.
To add the source to zskarte, you need to switch to expert view and than add the source, see https://www.zskarte.ch/help/expert-view/wms-source