A Jupyter server executes arbitrary code as its user, so an exposed or misconfigured server is a full remote shell for an attacker.
A running Jupyter Server can execute any code with the permissions of the user who started it. Treat access to it like SSH access.
Authentication. By default the server generates a random token and only listens on localhost. Keep both defaults whenever possible. Set a hashed password with jupyter server password, which writes it to the config directory. Never run with an empty token on a reachable interface, and avoid --allow-root outside containers.
Remote machines. The safest pattern is to keep the server on localhost and tunnel:
ssh -L 8888:localhost:8888 user@gpu-boxthen open http://localhost:8888 locally. If you must listen on a network interface (--ip 0.0.0.0), put it behind TLS (--certfile, --keyfile, or a reverse proxy) and a strong password or token.
Configuration lives in jupyter_server_config.py (generate with jupyter server --generate-config) using traitlets: c.ServerApp.ip, c.ServerApp.port, c.ServerApp.root_dir, c.IdentityProvider.token. Every option can also be passed on the command line, such as --ServerApp.port=9000. jupyter --paths shows where configs, data and runtime files live.
Teams. JupyterHub runs a hub that authenticates users (OAuth, LDAP, GitHub ...) and spawns a separate single-user server per person, on one machine, in Docker containers, or on Kubernetes (Zero to JupyterHub with Helm). Resource limits, idle culling and shared storage are configured at the hub level.
Remember that notebooks can contain malicious code or outputs; Jupyter marks notebooks as untrusted and disables JavaScript outputs until you trust them.
Example
# Remote GPU box: keep the server on localhost and tunnel to it
ssh -L 8888:localhost:8888 me@gpu-box
jupyter lab --no-browser --port 8888 # run on gpu-box (listens on localhost)
# Set a password instead of copying tokens around
jupyter server password # stores a hashed password
# Generate and edit the config file
jupyter server --generate-config # ~/.jupyter/jupyter_server_config.py
cat >> ~/.jupyter/jupyter_server_config.py <<'EOF'
c.ServerApp.ip = "127.0.0.1"
c.ServerApp.root_dir = "/srv/projects"
c.ServerApp.open_browser = False
EOF
jupyter --paths # config, data and runtime locations
# Teams: JupyterHub spawns one server per user (pip install jupyterhub)Remember
- A Jupyter server runs arbitrary code as its user: protect it like SSH
- Keep localhost and tokens; use SSH tunnels or TLS plus passwords for remote access
- Configure via traitlets (
c.ServerApp...); use JupyterHub for multi-user setups
Watch out for
- Starting
jupyter lab --ip 0.0.0.0with an empty token on a cloud VM, exposing a remote shell to the internet.