From 45cb18da4d43cacf11096dd441f5f72ea64ae1cd Mon Sep 17 00:00:00 2001 From: stellarshenson Date: Fri, 16 Jan 2026 16:27:45 +0100 Subject: [PATCH] feat: enhance traefik-host-based-routing with CIFS and cert installers - Add optional CIFS mount support via compose_cifs.yml and .env - Create install_cert.sh for Linux (multi-distro support) - Enhance install_cert.bat with folder argument and help flags - Fix compose_override.yml stray quote, add idle culler defaults - Enhance generate-certs.sh with generic CN and verification - Update start.sh/stop.sh to support ENABLE_CIFS from .env - Update README with CIFS and certificate installation docs --- .claude/JOURNAL.md | 3 + extra/traefik-host-based-routing/.env.example | 6 + extra/traefik-host-based-routing/.gitignore | 3 + extra/traefik-host-based-routing/README.md | 38 ++- .../compose_cifs.yml | 20 ++ .../compose_override.yml | 5 +- .../generate-certs.sh | 27 ++- .../install_cert.bat | 150 ++++++++++-- .../install_cert.sh | 229 ++++++++++++++++++ extra/traefik-host-based-routing/start.sh | 22 +- extra/traefik-host-based-routing/stop.sh | 18 +- 11 files changed, 478 insertions(+), 43 deletions(-) create mode 100644 extra/traefik-host-based-routing/.env.example create mode 100644 extra/traefik-host-based-routing/compose_cifs.yml create mode 100755 extra/traefik-host-based-routing/install_cert.sh diff --git a/.claude/JOURNAL.md b/.claude/JOURNAL.md index bad024d..b456c8d 100644 --- a/.claude/JOURNAL.md +++ b/.claude/JOURNAL.md @@ -162,3 +162,6 @@ This journal tracks substantive work on documents, diagrams, and documentation c 53. **Task - Create stop.sh script**: Added stop.sh to complement start.sh for platform shutdown
**Result**: Created stop.sh mirroring start.sh pattern - resolves script location via readlink/dirname, respects compose_override.yml if present, runs docker compose down --remove-orphans + +54. **Task - Enhance traefik-host-based-routing template**: Major improvements to deployment template with CIFS support and certificate installers
+ **Result**: Added optional CIFS mount support via compose_cifs.yml and .env.example (ENABLE_CIFS=1), created install_cert.sh for Linux (multi-distro: Debian/Ubuntu, RHEL/CentOS, Arch, Alpine, macOS) and enhanced install_cert.bat for Windows with folder argument and help flags, fixed compose_override.yml stray quote and added JUPYTERHUB_IDLE_CULLER_ENABLED/JUPYTERHUB_SIGNUP_ENABLED defaults, enhanced generate-certs.sh with generic CN for browser compatibility and verification output, updated start.sh/stop.sh to load .env and conditionally include compose_cifs.yml, updated README with CIFS instructions and certificate installation commands, added .env to .gitignore diff --git a/extra/traefik-host-based-routing/.env.example b/extra/traefik-host-based-routing/.env.example new file mode 100644 index 0000000..7badb17 --- /dev/null +++ b/extra/traefik-host-based-routing/.env.example @@ -0,0 +1,6 @@ +# Optional environment variables +# Copy to .env and customize + +# Enable CIFS mount for shared storage (0=disabled, 1=enabled) +# Requires compose_cifs.yml to be configured with NAS credentials +ENABLE_CIFS=0 diff --git a/extra/traefik-host-based-routing/.gitignore b/extra/traefik-host-based-routing/.gitignore index 414d185..02c6721 100644 --- a/extra/traefik-host-based-routing/.gitignore +++ b/extra/traefik-host-based-routing/.gitignore @@ -15,6 +15,9 @@ Thumbs.db # Docker .docker/ +# Environment (may contain credentials) +.env + # TLS certificates (private keys) certs/*.pem certs/**/*.pem diff --git a/extra/traefik-host-based-routing/README.md b/extra/traefik-host-based-routing/README.md index 971ea2a..d5ddad2 100644 --- a/extra/traefik-host-based-routing/README.md +++ b/extra/traefik-host-based-routing/README.md @@ -27,9 +27,13 @@ Template for deploying stellars-jupyterhub-ds with local Traefik reverse proxy a ``` _stellars_jupyterhub_ds/ compose_override.yml # Local Traefik + JupyterHub config - start.sh # Pull latest + start services + compose_cifs.yml # Optional CIFS mount configuration + start.sh # Clone/update + start services stop.sh # Stop services generate-certs.sh # Certificate generation script + install_cert.sh # Linux certificate installer + install_cert.bat # Windows certificate installer + .env.example # Example environment config certs/ tls.yml # Traefik TLS configuration _.yourdomain.example.com/ # Generated wildcard cert @@ -43,8 +47,19 @@ Template for deploying stellars-jupyterhub-ds with local Traefik reverse proxy a Edit `compose_override.yml` to customize: - Domain name (replace `YOURDOMAIN` placeholder) - Ports (default: 80/443) +- Environment variables (idle culler, signup) - Network name -- Additional services + +### Optional CIFS Mount + +To enable shared NAS storage for user containers: + +1. Edit `compose_cifs.yml` with your NAS credentials +2. Create `.env` from `.env.example`: + ```bash + cp .env.example .env + ``` +3. Set `ENABLE_CIFS=1` in `.env` ## Access @@ -52,13 +67,26 @@ After deployment: - JupyterHub: https://jupyterhub.yourdomain.example.com/ - Traefik: https://traefik.yourdomain.example.com -Import `certs/_./cert.pem` to browser for trusted HTTPS. +### Certificate Installation + +Import the self-signed certificate to your browser for trusted HTTPS: + +**Linux:** +```bash +./install_cert.sh certs/_.yourdomain.example.com/ +``` + +**Windows:** +```cmd +install_cert.bat certs\_.yourdomain.example.com\ +``` ## Commands ```bash -./start.sh # Pull latest + start services -./stop.sh # Stop all services +./start.sh # Clone repo (if missing) + start services +./start.sh --refresh # Pull latest upstream + start services +./stop.sh # Stop all services ``` To view logs: diff --git a/extra/traefik-host-based-routing/compose_cifs.yml b/extra/traefik-host-based-routing/compose_cifs.yml new file mode 100644 index 0000000..d5771b1 --- /dev/null +++ b/extra/traefik-host-based-routing/compose_cifs.yml @@ -0,0 +1,20 @@ +# ============================================================================= +# CIFS Volume Mount - Optional +# ============================================================================= +# +# Enable by setting ENABLE_CIFS=1 in .env +# +# Update credentials and mount path below before enabling. +# +# ============================================================================= + +volumes: + jupyterhub_shared: + driver: local + name: jupyterhub_shared + driver_opts: + type: cifs + device: //nas.example.com/shared + o: username=YOUR_USERNAME,password=YOUR_PASSWORD,uid=1000,gid=1000,vers=3.0 + +# EOF diff --git a/extra/traefik-host-based-routing/compose_override.yml b/extra/traefik-host-based-routing/compose_override.yml index 8daf9f9..6aa7a36 100644 --- a/extra/traefik-host-based-routing/compose_override.yml +++ b/extra/traefik-host-based-routing/compose_override.yml @@ -7,7 +7,7 @@ # ACCESS: https://jupyterhub.YOURDOMAIN/ or https://jupyterhub.localhost/ # TRUST: Import certs/_.YOURDOMAIN/cert.pem to browser # -# Replace YOURDOMAIN with your actual domain (e.g., lab.stellars-tech.eu) +# Replace YOURDOMAIN with your actual domain (e.g., lab.example.com) # # ============================================================================= @@ -68,6 +68,8 @@ services: ports: [] environment: - JUPYTERHUB_BASE_URL=/ + - JUPYTERHUB_IDLE_CULLER_ENABLED=1 + - JUPYTERHUB_SIGNUP_ENABLED=0 networks: - jupyterhub_network labels: @@ -75,7 +77,6 @@ services: # JupyterHub router (root path) - "traefik.http.routers.jupyterhub-rtr.rule=Host(`jupyterhub.YOURDOMAIN`) || Host(`jupyterhub.localhost`)" -" - "traefik.http.routers.jupyterhub-rtr.entrypoints=websecure" - "traefik.http.routers.jupyterhub-rtr.tls=true" - "traefik.http.routers.jupyterhub-rtr.service=jupyterhub-svc" diff --git a/extra/traefik-host-based-routing/generate-certs.sh b/extra/traefik-host-based-routing/generate-certs.sh index 6a09338..6544972 100755 --- a/extra/traefik-host-based-routing/generate-certs.sh +++ b/extra/traefik-host-based-routing/generate-certs.sh @@ -4,13 +4,16 @@ # ============================================================================= # # Usage: ./generate-certs.sh -# Example: ./generate-certs.sh lab.stellars-tech.eu +# Example: ./generate-certs.sh lab.example.com # # Creates: # certs/_.domain/cert.pem - Certificate (import to browser) # certs/_.domain/key.pem - Private key # certs/tls.yml - Traefik TLS configuration # +# Note: Uses generic CN to avoid browser CN validation issues across multiple +# domains. All domains are specified in SAN (Subject Alternative Name) field. +# # ============================================================================= set -e @@ -19,7 +22,7 @@ DOMAIN="${1:-}" if [ -z "$DOMAIN" ]; then echo "Usage: $0 " - echo "Example: $0 lab.stellars-tech.eu" + echo "Example: $0 lab.example.com" exit 1 fi @@ -32,16 +35,17 @@ echo "Generating self-signed certificate for *.${DOMAIN}" mkdir -p "$CERT_DIR" # Generate self-signed certificate +# Uses generic CN to avoid browser CN validation issues; domains are in SAN openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout "${CERT_DIR}/key.pem" \ -out "${CERT_DIR}/cert.pem" \ - -subj "/CN=*.${DOMAIN}" \ - -addext "subjectAltName=DNS:*.${DOMAIN},DNS:${DOMAIN},DNS:localhost,DNS:*.localhost" + -subj "/CN=DEV Certificate" \ + -addext "subjectAltName=DNS:*.${DOMAIN},DNS:${DOMAIN},DNS:*.app.localhost,DNS:app.localhost,DNS:*.localhost,DNS:localhost" # Generate Traefik TLS configuration cat > "$TLS_CONFIG" << EOF # TLS Configuration for self-signed certificates -# Wildcard cert: *.${DOMAIN} +# Wildcard cert: *.${DOMAIN}, *.localhost # Import cert.pem to browser for trusted HTTPS tls: @@ -57,12 +61,15 @@ tls: EOF echo "" -echo "Certificate generated successfully:" -echo " - ${CERT_DIR}/cert.pem (import to browser)" -echo " - ${CERT_DIR}/key.pem" -echo " - ${TLS_CONFIG}" +echo "Certificate generated:" +openssl x509 -in "${CERT_DIR}/cert.pem" -noout -subject -dates -ext subjectAltName + +echo "" +echo "Key verified:" +openssl rsa -in "${CERT_DIR}/key.pem" -check -noout + echo "" echo "Next steps:" echo " 1. Edit compose_override.yml - replace YOURDOMAIN with ${DOMAIN}" echo " 2. Import ${CERT_DIR}/cert.pem to your browser" -echo " 3. Run: make start" +echo " 3. Run: ./start.sh" diff --git a/extra/traefik-host-based-routing/install_cert.bat b/extra/traefik-host-based-routing/install_cert.bat index 25eac29..9edcbcc 100755 --- a/extra/traefik-host-based-routing/install_cert.bat +++ b/extra/traefik-host-based-routing/install_cert.bat @@ -1,10 +1,29 @@ @echo off setlocal enabledelayedexpansion +REM Check for help flag +if "%~1"=="-h" goto :show_help +if "%~1"=="--help" goto :show_help +if "%~1"=="/?" goto :show_help + +REM Optional argument: folder to search for certificates (default: current directory) +set "CERT_DIR=%~1" +if "%CERT_DIR%"=="" set "CERT_DIR=." + +REM Check if directory exists +if not exist "%CERT_DIR%\" ( + echo Error: Directory '%CERT_DIR%' not found. + echo Use --help for usage information. + pause + exit /b 1 +) + echo ============================================ echo Certificate Installer - Root Trust Store echo ============================================ echo. +echo Scanning directory: %CERT_DIR% +echo. echo WARNING: This script installs certificates echo into your Trusted Root Certification echo Authorities store. @@ -32,47 +51,134 @@ if /i not "%proceed%"=="Y" ( ) echo. -set "found=0" +echo Scanning for certificate and key files... +echo. -for %%F in (*.cer *.crt *.pem *.der) do ( +set "found=0" +set "certcount=0" +set "keycount=0" + +for %%F in ("%CERT_DIR%\*.cer" "%CERT_DIR%\*.crt" "%CERT_DIR%\*.pem" "%CERT_DIR%\*.der" "%CERT_DIR%\*.key" "%CERT_DIR%\*.p12" "%CERT_DIR%\*.pfx") do ( set "found=1" echo -------------------------------------------- echo File: %%F echo -------------------------------------------- - REM Get certificate details using PowerShell - powershell -Command ^ - "$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('%%F'); " ^ - "Write-Host 'Subject (CN):' $cert.Subject; " ^ - "Write-Host 'Issuer:' $cert.Issuer; " ^ - "Write-Host 'Valid From:' $cert.NotBefore; " ^ - "Write-Host 'Valid To:' $cert.NotAfter; " ^ - "Write-Host 'Thumbprint:' $cert.Thumbprint; " ^ - "$san = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq 'Subject Alternative Name' }; " ^ - "if ($san) { Write-Host 'SANs:' $san.Format(1) } else { Write-Host 'SANs: (none)' }" + REM Create temp PowerShell script for reliable execution + ( + echo $file = '%%F' + echo $ext = [System.IO.Path]::GetExtension^($file^).ToLower^(^) + echo $content = Get-Content $file -Raw -ErrorAction SilentlyContinue + echo. + echo # Check for private key patterns + echo $isKey = $false + echo if ^($ext -eq '.key'^) { $isKey = $true } + echo elseif ^($content -match '-----BEGIN ^(RSA ^|EC ^|ENCRYPTED ^|^)PRIVATE KEY-----'^) { $isKey = $true } + echo elseif ^($content -match '-----BEGIN OPENSSH PRIVATE KEY-----'^) { $isKey = $true } + echo. + echo if ^($isKey^) { + echo Write-Host '[PRIVATE KEY] - Skipping ^(not a certificate^)' -ForegroundColor Yellow + echo Write-Host 'Type: Private Key file' + echo exit 1 + echo } + echo. + echo # Check for PKCS#12/PFX files + echo if ^($ext -eq '.p12' -or $ext -eq '.pfx'^) { + echo Write-Host '[PKCS#12/PFX] - Contains certificate + private key bundle' -ForegroundColor Yellow + echo Write-Host 'Note: Use certutil or MMC to import PFX files with private keys' + echo exit 2 + echo } + echo. + echo # Try to load as certificate + echo try { + echo $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2^($file^) + echo Write-Host '[CERTIFICATE]' -ForegroundColor Green + echo Write-Host 'Subject ^(CN^):' $cert.Subject + echo Write-Host 'Issuer:' $cert.Issuer + echo Write-Host 'Valid From:' $cert.NotBefore + echo Write-Host 'Valid To:' $cert.NotAfter + echo Write-Host 'Thumbprint:' $cert.Thumbprint + echo $san = $cert.Extensions ^| Where-Object { $_.Oid.FriendlyName -eq 'Subject Alternative Name' } + echo if ^($san^) { Write-Host 'SANs:' $san.Format^(1^) } else { Write-Host 'SANs: ^(none^)' } + echo exit 0 + echo } catch { + echo Write-Host '[UNKNOWN/INVALID] - Could not parse as certificate' -ForegroundColor Red + echo Write-Host 'Error:' $_.Exception.Message + echo exit 3 + echo } + ) > "%TEMP%\certcheck.ps1" + + powershell -ExecutionPolicy Bypass -File "%TEMP%\certcheck.ps1" + set "exitcode=!errorlevel!" echo. - set /p "confirm=Install this certificate to Trusted Root store? (Y/N): " - if /i "!confirm!"=="Y" ( - echo Installing %%F... - powershell -Command "Import-Certificate -FilePath '%%F' -CertStoreLocation Cert:\CurrentUser\Root" >nul 2>&1 - if !errorlevel! equ 0 ( - echo [SUCCESS] Certificate installed. + REM Only prompt for installation if it's a valid certificate (exit code 0) + if "!exitcode!"=="0" ( + set /p "confirm=Install this certificate to Trusted Root store? (Y/N): " + + if /i "!confirm!"=="Y" ( + echo Installing %%F... + powershell -Command "Import-Certificate -FilePath '%%F' -CertStoreLocation Cert:\CurrentUser\Root" >nul 2>&1 + if !errorlevel! equ 0 ( + echo [SUCCESS] Certificate installed. + set /a "certcount+=1" + ) else ( + echo [ERROR] Failed to install certificate. Try running as Administrator. + ) ) else ( - echo [ERROR] Failed to install certificate. Try running as Administrator. + echo Skipped %%F ) + ) else if "!exitcode!"=="1" ( + set /a "keycount+=1" + echo [Skipped - Private key] + ) else if "!exitcode!"=="2" ( + echo [Skipped - Use different tool for PFX import] ) else ( - echo Skipped %%F + echo [Skipped - Invalid or unrecognized file] ) echo. ) +REM Cleanup temp file +del "%TEMP%\certcheck.ps1" 2>nul + if "!found!"=="0" ( - echo No certificate files found in current directory. - echo Supported extensions: .cer, .crt, .pem, .der + echo No certificate or key files found in '%CERT_DIR%'. + echo Supported extensions: .cer, .crt, .pem, .der, .key, .p12, .pfx ) +echo ============================================ +echo Summary: +echo Certificates installed: !certcount! +echo Private keys found (skipped): !keycount! +echo ============================================ echo. echo Done. pause +exit /b + +:show_help +echo Certificate Installer - Install certificates to Windows trust store +echo. +echo Usage: install_cert.bat [OPTIONS] [DIRECTORY] +echo. +echo Arguments: +echo DIRECTORY Folder to search for certificates (default: current directory) +echo. +echo Options: +echo -h, --help, /? Show this help message and exit +echo. +echo Supported file types: +echo .cer, .crt, .pem, .der - X.509 certificates (will be installed) +echo .key - Private keys (skipped) +echo .p12, .pfx - PKCS#12 bundles (skipped - use different tool) +echo. +echo Examples: +echo install_cert.bat # Scan current directory +echo install_cert.bat C:\path\to\certs # Scan specific directory +echo install_cert.bat .\my-certs # Scan relative path +echo. +echo Note: May require Administrator privileges for system-wide installation. +pause +exit /b diff --git a/extra/traefik-host-based-routing/install_cert.sh b/extra/traefik-host-based-routing/install_cert.sh new file mode 100755 index 0000000..a55a3b2 --- /dev/null +++ b/extra/traefik-host-based-routing/install_cert.sh @@ -0,0 +1,229 @@ +#!/bin/bash + +# Show help +show_help() { + cat << 'EOF' +Certificate Installer - Install certificates to system trust store + +Usage: install_cert.sh [OPTIONS] [DIRECTORY] + +Arguments: + DIRECTORY Folder to search for certificates (default: current directory) + +Options: + -h, --help Show this help message and exit + +Supported file types: + .cer, .crt, .pem, .der - X.509 certificates (will be installed) + .key - Private keys (skipped) + .p12, .pfx - PKCS#12 bundles (skipped - use different tool) + +Examples: + install_cert.sh # Scan current directory + install_cert.sh /path/to/certs # Scan specific directory + install_cert.sh ./my-certs # Scan relative path + +Note: Requires sudo privileges for system-wide certificate installation. +EOF + exit 0 +} + +# Parse arguments +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + show_help +fi + +# Optional argument: folder to search for certificates (default: current directory) +CERT_DIR="${1:-.}" + +# Resolve to absolute path and check if exists +if [ ! -d "$CERT_DIR" ]; then + echo "Error: Directory '$CERT_DIR' not found." + echo "Use --help for usage information." + exit 1 +fi + +echo "============================================" +echo " Certificate Installer - Root Trust Store" +echo "============================================" +echo "" +echo " Scanning directory: $CERT_DIR" +echo "" +echo " WARNING: This script installs certificates" +echo " into your system's trusted root store." +echo "" +echo " This is intended for custom self-signed" +echo " certificates from TRUSTED sources only." +echo "" +echo " *** INSTALLING UNKNOWN CERTIFICATES IS ***" +echo " *** EXTREMELY DANGEROUS! ***" +echo "" +echo " A malicious root certificate can allow" +echo " attackers to intercept ALL your encrypted" +echo " traffic, including passwords, banking," +echo " and personal data." +echo "" +echo " Only proceed if you know and trust the" +echo " source of these certificates!" +echo "============================================" +echo "" +read -p "Do you want to continue? (Y/N): " proceed + +if [[ ! "$proceed" =~ ^[Yy]$ ]]; then + echo "Aborted." + exit 0 +fi + +echo "" +echo "Scanning for certificate and key files..." +echo "" + +found=0 +certcount=0 +keycount=0 + +# Detect OS for correct certificate installation path +install_cert() { + local certfile="$1" + + if [ -f /etc/debian_version ]; then + # Debian/Ubuntu + sudo cp "$certfile" /usr/local/share/ca-certificates/ + sudo update-ca-certificates + elif [ -f /etc/redhat-release ]; then + # RHEL/CentOS/Fedora + sudo cp "$certfile" /etc/pki/ca-trust/source/anchors/ + sudo update-ca-trust + elif [ -f /etc/arch-release ]; then + # Arch Linux + sudo cp "$certfile" /etc/ca-certificates/trust-source/anchors/ + sudo trust extract-compat + elif [ -f /etc/alpine-release ]; then + # Alpine Linux + sudo cp "$certfile" /usr/local/share/ca-certificates/ + sudo update-ca-certificates + elif [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$certfile" + else + echo "[ERROR] Unknown OS. Please install manually." + return 1 + fi + return 0 +} + +for file in "$CERT_DIR"/*.cer "$CERT_DIR"/*.crt "$CERT_DIR"/*.pem "$CERT_DIR"/*.der "$CERT_DIR"/*.key "$CERT_DIR"/*.p12 "$CERT_DIR"/*.pfx; do + # Skip if no files match the pattern + [ -e "$file" ] || continue + + found=1 + echo "--------------------------------------------" + echo "File: $file" + echo "--------------------------------------------" + + ext="${file##*.}" + ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]') + + # Check for private key + is_key=false + + if [ "$ext" = "key" ]; then + is_key=true + elif [ -f "$file" ] && grep -q -E -- "-----BEGIN (RSA |EC |ENCRYPTED )?PRIVATE KEY-----|-----BEGIN OPENSSH PRIVATE KEY-----" "$file" 2>/dev/null; then + is_key=true + fi + + if [ "$is_key" = true ]; then + echo -e "\033[33m[PRIVATE KEY]\033[0m - Skipping (not a certificate)" + echo "Type: Private Key file" + echo "" + echo "[Skipped - Private key]" + ((keycount++)) + echo "" + continue + fi + + # Check for PKCS#12/PFX files + if [ "$ext" = "p12" ] || [ "$ext" = "pfx" ]; then + echo -e "\033[33m[PKCS#12/PFX]\033[0m - Contains certificate + private key bundle" + echo "Note: Use 'openssl pkcs12' to extract certificate, or import directly with browser" + echo "" + echo "[Skipped - Use different tool for PFX import]" + echo "" + continue + fi + + # Try to parse as certificate using openssl + cert_info=$(openssl x509 -in "$file" -noout -subject -issuer -dates -fingerprint -ext subjectAltName 2>/dev/null) + + if [ $? -eq 0 ]; then + echo -e "\033[32m[CERTIFICATE]\033[0m" + + # Extract and display certificate details + subject=$(openssl x509 -in "$file" -noout -subject 2>/dev/null | sed 's/subject=/Subject (CN): /') + issuer=$(openssl x509 -in "$file" -noout -issuer 2>/dev/null | sed 's/issuer=/Issuer: /') + startdate=$(openssl x509 -in "$file" -noout -startdate 2>/dev/null | sed 's/notBefore=/Valid From: /') + enddate=$(openssl x509 -in "$file" -noout -enddate 2>/dev/null | sed 's/notAfter=/Valid To: /') + fingerprint=$(openssl x509 -in "$file" -noout -fingerprint -sha256 2>/dev/null | sed 's/sha256 Fingerprint=/Thumbprint (SHA256): /' | sed 's/SHA256 Fingerprint=/Thumbprint (SHA256): /') + san=$(openssl x509 -in "$file" -noout -ext subjectAltName 2>/dev/null | grep -v "X509v3 Subject Alternative Name:") + + echo "$subject" + echo "$issuer" + echo "$startdate" + echo "$enddate" + echo "$fingerprint" + + if [ -n "$san" ]; then + echo "SANs:$san" + else + echo "SANs: (none)" + fi + + echo "" + read -p "Install this certificate to Trusted Root store? (Y/N): " confirm + + if [[ "$confirm" =~ ^[Yy]$ ]]; then + echo "Installing $file..." + + # Convert to PEM if needed (for DER format) + if [ "$ext" = "der" ]; then + tmpfile=$(mktemp) + openssl x509 -in "$file" -inform DER -out "$tmpfile" -outform PEM + install_cert "$tmpfile" + result=$? + rm -f "$tmpfile" + else + install_cert "$file" + result=$? + fi + + if [ $result -eq 0 ]; then + echo "[SUCCESS] Certificate installed." + ((certcount++)) + else + echo "[ERROR] Failed to install certificate. Make sure you have sudo privileges." + fi + else + echo "Skipped $file" + fi + else + echo -e "\033[31m[UNKNOWN/INVALID]\033[0m - Could not parse as certificate" + echo "Error: File is not a valid X.509 certificate or format not recognized" + echo "" + echo "[Skipped - Invalid or unrecognized file]" + fi + echo "" +done + +if [ "$found" -eq 0 ]; then + echo "No certificate or key files found in '$CERT_DIR'." + echo "Supported extensions: .cer, .crt, .pem, .der, .key, .p12, .pfx" +fi + +echo "============================================" +echo "Summary:" +echo " Certificates installed: $certcount" +echo " Private keys found (skipped): $keycount" +echo "============================================" +echo "" +echo "Done." diff --git a/extra/traefik-host-based-routing/start.sh b/extra/traefik-host-based-routing/start.sh index 42289a2..1845689 100755 --- a/extra/traefik-host-based-routing/start.sh +++ b/extra/traefik-host-based-routing/start.sh @@ -1,5 +1,6 @@ #!/bin/bash -# Start JupyterHub platform with latest upstream +# Start JupyterHub platform +# Usage: ./start.sh [--refresh] set -e @@ -9,6 +10,14 @@ REPO_URL="https://github.com/stellarshenson/stellars-jupyterhub-ds.git" REPO_DIR="stellars-jupyterhub-ds" REFRESH=false +# Default configuration (override via .env) +ENABLE_CIFS="${ENABLE_CIFS:-0}" + +# Load environment variables if .env exists +if [[ -f .env ]]; then + source .env +fi + # Parse arguments while [[ $# -gt 0 ]]; do case $1 in @@ -37,9 +46,16 @@ else git clone "$REPO_URL" fi +# Build compose command with optional CIFS mount +COMPOSE_FILES="-f stellars-jupyterhub-ds/compose.yml -f compose_override.yml" +if [[ "${ENABLE_CIFS}" == "1" ]]; then + echo "CIFS mount enabled" + COMPOSE_FILES="${COMPOSE_FILES} -f compose_cifs.yml" +fi + echo "Starting JupyterHub platform..." -docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml pull +docker compose ${COMPOSE_FILES} pull docker pull stellars/stellars-jupyterlab-ds:latest -docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml up -d --no-build +docker compose ${COMPOSE_FILES} up -d --no-build echo "Done. Access: https://jupyterhub.YOURDOMAIN/" diff --git a/extra/traefik-host-based-routing/stop.sh b/extra/traefik-host-based-routing/stop.sh index 787d8dd..d35ffe0 100755 --- a/extra/traefik-host-based-routing/stop.sh +++ b/extra/traefik-host-based-routing/stop.sh @@ -3,7 +3,23 @@ set -e +cd "$(dirname "$0")" + +# Default configuration (override via .env) +ENABLE_CIFS="${ENABLE_CIFS:-0}" + +# Load environment variables if .env exists +if [[ -f .env ]]; then + source .env +fi + +# Build compose command with optional CIFS mount +COMPOSE_FILES="-f stellars-jupyterhub-ds/compose.yml -f compose_override.yml" +if [[ "${ENABLE_CIFS}" == "1" ]]; then + COMPOSE_FILES="${COMPOSE_FILES} -f compose_cifs.yml" +fi + echo "Stopping services..." -docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml down +docker compose ${COMPOSE_FILES} down echo "Done."