Add the sftpgo server and a web server

This commit is contained in:
Eric Coissac
2025-10-15 15:55:43 +02:00
parent ae77f71b6c
commit a3608759c5
8 changed files with 191 additions and 83 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/jupyterhub_volumes/users
/jupyterhub_volumes/shared
/jupyterhub_volumes/jupyterhub
/jupyterhub_volumes/caddy

43
Caddyfile Normal file
View File

@@ -0,0 +1,43 @@
http:// {
root * /srv
file_server
# Proxy pour SFTPGo avec réécriture du chemin
# Proxy pour l'interface Web de SFTPGo
# SFTPGo n'a pas de support natif pour les sous-chemins
# Il faut proxy /web/ et /static/ séparément
handle /web/* {
reverse_proxy http://jupytersftp:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
handle /static/* {
reverse_proxy http://jupytersftp:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
handle /api/* {
reverse_proxy http://jupytersftp:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
handle /sftp/* {
uri strip_prefix /sftp
reverse_proxy http://jupytersftp:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
# Proxy vers JupyterHub
handle /jupyter/* {
reverse_proxy http://jupyterhub:8000
}
}

View File

@@ -4,9 +4,10 @@ services:
context: . context: .
dockerfile: Dockerfile.hub dockerfile: Dockerfile.hub
container_name: jupyterhub container_name: jupyterhub
hostname: jupyterhub
image: jupyterhub-hub:latest image: jupyterhub-hub:latest
ports: expose:
- "8888:8000" - "8000"
volumes: volumes:
# Access to Docker socket to spawn student containers # Access to Docker socket to spawn student containers
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
@@ -25,6 +26,47 @@ services:
# Optional environment variables # Optional environment variables
DOCKER_NOTEBOOK_DIR: /home/jovyan/work DOCKER_NOTEBOOK_DIR: /home/jovyan/work
# ---------- Nginx ----------
caddy:
container_name: jupyterhub-caddy
hostname: jupytercaddy
image: caddy:latest
ports:
- "8888:80"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- jupyterhub-caddy-data:/data
- jupyterhub-caddy-config:/config
- jupyterhub-web:/srv # Votre app
networks:
- jupyterhub-network
restart: unless-stopped
# ---------- SFTPGo ----------
sftpgo:
image: drakkan/sftpgo:latest
container_name: jupyterhub-sftpgo
hostname: jupytersftp
command: sftpgo serve --loaddata-from /config/local_config.json --loaddata-clean
expose:
- "2022"
- "8080"
environment:
SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN: true
SFTPGO_DEFAULT_ADMIN_USERNAME: admin
SFTPGO_DEFAULT_ADMIN_PASSWORD: admin2025
SFTPGO_HTTPD__BINDINGS__0__CLIENT_IP_PROXY_HEADER: X-Real-IP
volumes:
- jupyterhub-shared:/volumes/shared
- jupyterhub-course:/volumes/course
- jupyterhub-web:/volumes/web
- ./sftpgo_config.json:/config/local_config.json:ro
networks:
- jupyterhub-network
restart: unless-stopped
networks: networks:
jupyterhub-network: jupyterhub-network:
name: jupyterhub-network name: jupyterhub-network
@@ -32,6 +74,44 @@ networks:
volumes: volumes:
jupyterhub-data: jupyterhub-data:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/jupyterhub
jupyterhub-shared: jupyterhub-shared:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/shared
jupyterhub-course: jupyterhub-course:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/course
jupyterhub-web:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/web
jupyterhub-caddy-data:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/caddy/data
jupyterhub-caddy-config:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/caddy/config
jupyterhub-users:
driver: local
driver_opts:
type: none
o: bind
device: ./jupyterhub_volumes/users

0
install_packages.sh Normal file → Executable file
View File

View File

@@ -1,6 +1,6 @@
import os import os
# Base configuration # Base configuration coucou
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner' c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# Enable debug logs # Enable debug logs
@@ -88,79 +88,8 @@ c.Authenticator.allow_all = True
c.Authenticator.admin_users = {'admin'} c.Authenticator.admin_users = {'admin'}
# Listening port # Listening port
c.JupyterHub.bind_url = 'http://0.0.0.0:8000' c.JupyterHub.bind_url = 'http://0.0.0.0:8000/jupyter/'
# Timeout # Timeout
c.Spawner.start_timeout = 300 c.Spawner.start_timeout = 300
c.Spawner.http_timeout = 120 c.Spawner.http_timeout = 120
import os
# Configuration de base
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# Activer les logs de debug
c.JupyterHub.log_level = 'DEBUG'
c.Spawner.debug = True
# Image Docker à utiliser pour les containers étudiants
c.DockerSpawner.image = 'jupyterhub-student:latest'
# Réseau Docker (créez-le avec: docker network create jupyterhub-network)
c.DockerSpawner.network_name = 'jupyterhub-network'
# Connexion au socket Docker d'OrbStack depuis le container hub
c.DockerSpawner.client_kwargs = {'base_url': 'unix:///var/run/docker.sock'}
# IMPORTANT : URL interne pour communiquer entre containers
# Le hub container communique avec les user containers via le réseau Docker
c.JupyterHub.hub_ip = '0.0.0.0'
c.JupyterHub.hub_connect_ip = 'jupyterhub'
# Configuration réseau pour les containers étudiants
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.network_name = 'jupyterhub-network'
c.DockerSpawner.extra_host_config = {'network_mode': 'jupyterhub-network'}
# Supprimer les containers après déconnexion (optionnel, mettre False pour garder les containers)
c.DockerSpawner.remove = True
# Nommage des containers
c.DockerSpawner.name_template = "jupyter-{username}"
# Montage de volumes pour persister les données des étudiants
# Définir la racine à /home/jovyan pour voir tous les dossiers
notebook_dir = '/home/jovyan/work'
c.DockerSpawner.notebook_dir = notebook_dir
# Volume personnel pour chaque étudiant + volume partagé
c.DockerSpawner.volumes = {
# Volume personnel (persistant) - monté dans work/
'jupyterhub-user-{username}': '/home/jovyan/work',
# Volume partagé entre tous les étudiants
'jupyterhub-shared': '/home/jovyan/work/shared',
# Volume partagé en lecture seule pour les fichiers du cours (optionnel)
'jupyterhub-course': {
'bind': '/home/jovyan/work/course',
'mode': 'ro' # read-only
}
}
# Configuration de la mémoire et CPU (ajustez selon vos besoins)
c.DockerSpawner.mem_limit = '2G'
c.DockerSpawner.cpu_limit = 1.0
# Pour créer une liste d'utilisateurs autorisés, décommentez et modifiez:
# c.Authenticator.allowed_users = {'etudiant1', 'etudiant2', 'etudiant3'}
# Ou autoriser n'importe quel utilisateur avec le bon mot de passe:
c.Authenticator.allow_all = True
# Configuration admin
c.Authenticator.admin_users = {'admin'}
# Port d'écoute
c.JupyterHub.bind_url = 'http://0.0.0.0:8000'
# Timeout
c.Spawner.start_timeout = 300
c.Spawner.http_timeout = 120

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Course Portal</title>
</head>
<body>
<h1>Welcome</h1>
<ul>
<li><a href="/jupyter/">JupyterHub</a></li>
<li><a href="/static/">Static Site</a></li>
</ul>
</body>
</html>

45
sftpgo_config.json Normal file
View File

@@ -0,0 +1,45 @@
{
"folders": [
{
"name": "shared_data",
"mapped_path": "/volumes/shared",
"description": "Dossier partagé entre utilisateurs",
"filesystem": {
"provider": 0
}
},
{
"name": "web_site",
"mapped_path": "/volumes/web",
"description": "Site web static",
"filesystem": {
"provider": 0
}
}
],
"users": [
{
"username": "admin",
"password": "admin2025",
"status": 1,
"home_dir": "/volumes/course",
"permissions": {
"/": ["*"]
},
"virtual_folders": [
{
"name": "shared_data",
"virtual_path": "/shared",
"quota_size": -1,
"quota_files": -1
},
{
"name": "web_site",
"virtual_path": "/web",
"quota_size": -1,
"quota_files": -1
}
]
}
]
}

View File

@@ -39,16 +39,10 @@ echo ""
echo -e "${BLUE}🔨 Building JupyterHub image...${NC}" echo -e "${BLUE}🔨 Building JupyterHub image...${NC}"
docker build -t jupyterhub-hub:latest -f Dockerfile.hub . docker build -t jupyterhub-hub:latest -f Dockerfile.hub .
# Create volumes if they don't exist
echo ""
echo -e "${BLUE}💾 Creating shared volumes...${NC}"
docker volume create jupyterhub-shared 2>/dev/null || echo " Volume jupyterhub-shared already exists"
docker volume create jupyterhub-course 2>/dev/null || echo " Volume jupyterhub-course already exists"
# Start the stack # Start the stack
echo "" echo ""
echo -e "${BLUE}🚀 Starting JupyterHub...${NC}" echo -e "${BLUE}🚀 Starting JupyterHub...${NC}"
docker-compose up -d docker-compose up -d --remove-orphans
# Wait for service to be ready # Wait for service to be ready
echo "" echo ""