From 6606b874e595291e0c16124433e135ff4c1acbcd Mon Sep 17 00:00:00 2001
From: DerGrumpf
Date: Mon, 15 Sep 2025 21:14:54 +0200
Subject: [PATCH] Fixed: Nginx WebSocket configuration causing Single User
Servers to miss out api requests
---
.env_example | 3 ++-
jupyterhub/jupyterhub_config.py | 16 ++++++++++++----
nginx/conf.d/jupyterhub.conf | 7 +++++--
nginx/nginx.conf | 7 +++++++
4 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/.env_example b/.env_example
index 0d02285..9a207aa 100644
--- a/.env_example
+++ b/.env_example
@@ -14,13 +14,14 @@ ENABLE_LAB=1
SPAWNER_DEFAULT_URL=/lab
NOTEBOOK_MEMORY_LIMIT=500M
NOTEBOOK_CPU_LIMIT=1.0
+NOTEBOOK_IMAGE=jupyter/base-notebook:latest
HUB_IP=jupyterhub # Name of the Docker container
DOCKER_NOTEBOOK_DIR=/home/jovyan/work
DOCKER_SPAWNER_DEBUG=0 # Set to non Zero to enable
# Docker
COMPOSE_PROJECT_NAME=ifn_stack
-DOCKER_NETWORK_NAME=jupyter_network
+DOCKER_NETWORK_NAME=jupyterhub-network
POSTGRES_PORT=5432
JUPYTERHUB_PORT=8000
NGINX_HTTP_PORT=8080
diff --git a/jupyterhub/jupyterhub_config.py b/jupyterhub/jupyterhub_config.py
index 431eeef..5396880 100644
--- a/jupyterhub/jupyterhub_config.py
+++ b/jupyterhub/jupyterhub_config.py
@@ -65,16 +65,24 @@ port = int(os.environ.get("JUPYTERHUB_PORT", "8000"))
base_url = os.environ.get("JUPYTERHUB_BASE_URL", "/jupyter/")
c.JupyterHub.bind_url = f"http://0.0.0.0:{port}{base_url}"
-# Database configuration
-c.JupyterHub.db_url = f"postgresql://{os.environ['POSTGRES_USER']}:{os.environ['POSTGRES_PASSWORD']}@{os.environ['POSTGRES_HOST']}:5432/{os.environ['POSTGRES_DB']}"
-# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite'
+# Mission Critical this should be the service name not the container name
+# without this option containers cant reach the api endpoint
+# this is due to nginx external rounting and might help
+# migration this project to a cluster setup
+c.JupyterHub.hub_connect_ip = "jupyterhub"
+# Database configuration
+p_user = os.environ["POSTGRES_USER"]
+p_pass = os.environ["POSTGRES_PASSWORD"]
+p_host = os.environ["POSTGRES_HOST"]
+p_db = os.environ["POSTGRES_DB"]
+c.JupyterHub.db_url = f"postgresql://{p_user}:{p_pass}@{p_host}:5432/{p_db}"
+# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite'
# Authenticator configuration - NativeAuthenticator
c.JupyterHub.authenticator_class = NativeAuthenticator
# Native Authenticator settings
-# c.NativeAuthenticator.create_system_users = True
c.NativeAuthenticator.minimum_password_length = int(
os.environ.get("NATIVE_AUTH_MIN_PASSWORD_LENGTH", "8")
)
diff --git a/nginx/conf.d/jupyterhub.conf b/nginx/conf.d/jupyterhub.conf
index cb48e03..7957a65 100644
--- a/nginx/conf.d/jupyterhub.conf
+++ b/nginx/conf.d/jupyterhub.conf
@@ -1,4 +1,3 @@
-# nginx/conf.d/jupyterhub.conf
server {
listen 80;
server_name _; # Respond to all hostnames
@@ -14,8 +13,12 @@ server {
# WebSocket support (crucial for Jupyter)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
+ proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400;
+ proxy_send_timeout 86400;
+
+ # Disable buffering for WebSocket
+ proxy_buffering off;
# Handle large file uploads
client_max_body_size 100M;
diff --git a/nginx/nginx.conf b/nginx/nginx.conf
index 4a3f652..49e5a3b 100644
--- a/nginx/nginx.conf
+++ b/nginx/nginx.conf
@@ -11,6 +11,13 @@ http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
+ # WebSocket connection mapping
+ map $http_upgrade $connection_upgrade {
+ default upgrade;
+ '' close;
+ }
+
+
# Log format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '