Website review
This review may include AI-generated content and is not individually verified. Domain, certificate and other facts come from the observed data on this page.
What is Jupyter Server?
Jupyter Server is the backend that supplies the core services, APIs, and REST endpoints that Jupyter web applications run on. It is not a notebook interface itself: it is the layer beneath interfaces such as JupyterLab, Notebook, and NbClassic, handling the server-side work they depend on. The documentation describes it as a replacement for the Tornado web server previously embedded in Jupyter Notebook, and recommends that Jupyter web applications migrate to it.
What it does in practice
- Serves the REST API and WebSocket kernel protocols that front ends use to run code, manage files, and talk to kernels.
- Provides extension points, so applications and services can be built on its framework and services rather than reimplementing server plumbing.
- Supports operational concerns such as configuration, logging, security, and running a public server.
Who it is for
The documentation splits its audience deliberately, which is a useful signal about the project's scope:
| Audience | Typical concern |
|---|---|
| Users | Installing, configuring, and launching a server to use Jupyter applications |
| Operators | Deploying to others, managing extensions, security, logging, migration from Notebook Server |
| Developers | Writing server extensions and web applications against the API |
| Contributors | Working directly on the Jupyter Server library |
Extensions listed in the documentation illustrate the range: JupyterLab as a computational environment, Jupyter Scheduler for running notebooks as jobs, jupyter-collaboration for shared documents, and Cylc UI Server for monitoring workflows.
A concrete next step
If you are choosing where to start, decide by role. Using Jupyter applications as an end user, begin with installation and configuration rather than the API. Deploying for a team, read the operator material on managing extensions, security, and migration. Building on top of it, start with the architecture diagrams and the REST API before writing an extension. General documentation for the wider ecosystem is at Project Jupyter, and the source code and issue tracker are at GitHub.
How do I migrate from the classic Notebook Server to Jupyter Server?
Migration means swapping the backend that serves your Jupyter web application: Jupyter Server replaces the Tornado Web Server that shipped inside classic Jupyter Notebook. The front end you use (Notebook, JupyterLab, NbClassic) then runs on top of Jupyter Server instead of the old Notebook server.
The official path is documented under Migrating from Notebook Server in Jupyter Server documentation, which also covers running Jupyter Notebook on Jupyter Server. Treat that page as your primary checklist rather than improvising.
Decide what you are actually migrating
| Situation | What changes | Typical approach |
|---|---|---|
| You just want to keep using the classic Notebook UI | Backend only; the interface stays familiar | Run Notebook as a Jupyter Server extension (NbClassic is listed as an example extension) |
| You are deploying for other people | Server configuration, extensions, security and logging settings | Follow the Operators section: managing extensions, configuring extensions, running a public server, security, logging |
| You are building a custom web app or extension | You target Jupyter Server's REST API and extension framework | Follow the Developers section: architecture diagrams, REST API, server extensions, contents API, file save hooks |
| You contribute to the library itself | Development setup and team processes | Follow the Contributors section |
Practical migration steps
- Identify every Notebook Server configuration file, startup script, and custom extension in your current deployment. Extensions are the usual source of breakage, because they must be compatible with Jupyter Server's framework rather than the old Notebook server.
- Install Jupyter Server and, if you still need the classic interface, the extension that provides it.
- Port your settings into Jupyter Server configuration, checking the "Configuring a Jupyter Server" and "Configuring Extensions" pages rather than copying old config blindly.
- Re-check security and authentication settings before exposing anything publicly — the docs separate "Security in the Jupyter Server" from "Security in notebook documents," and both matter.
- Test with a bare server launch first ("Launching a bare Jupyter Server"), then add extensions one at a time so you can attribute failures.
A concrete scenario
Suppose you run a shared Notebook Server for a small team, with two custom extensions: one for resource monitoring and one for scheduled notebook runs. Before migrating, confirm each extension has a Jupyter Server–compatible version. The documentation lists Jupyter Resource Usage and Jupyter Scheduler as examples of Jupyter Server extensions, so those categories of functionality exist in the new model — but your specific extension still needs to be updated or replaced. After migrating, verify that authentication, file access paths, and kernel connectivity behave the same for your users, since those are the areas where a backend swap shows up first.
Next step
Open the "Migrating from Notebook Server" page in Jupyter Server documentation and work through it alongside the Operators pages for your deployment. If your setup is a plain local install, the Users section (installation, configuration, launching a bare server) is enough. If you maintain extensions, read the Developers section before you start, because extension compatibility usually determines how long the migration takes.
What steps are needed to run a public Jupyter Server securely?
Running a public Jupyter Server securely means treating it as an internet-facing service, not a local notebook. You need authentication, TLS, network controls, and a clear decision about who can reach the server.
Minimum steps
- Decide whether it must be public at all. If a VPN, SSH tunnel, or reverse proxy with IP allowlisting can serve your users, prefer that. Public exposure increases the attack surface and makes every configuration mistake more dangerous.
- Enable authentication. Jupyter Server ships with token-based authentication by default, and you can configure a password instead. Never disable authentication on a public server. Create a strong token or password and store it outside the repository.
- Terminate TLS. Place the server behind a reverse proxy such as Nginx, Caddy, or Apache with a valid certificate, or configure TLS directly. Without HTTPS, tokens and notebook contents travel in cleartext.
- Bind to a controlled interface. Bind the server to
127.0.0.1and let the proxy handle external traffic. This prevents direct access to the backend port. - Restrict origins and headers. Set allowed origins to your real domain, and configure the proxy to forward only the headers you need. This reduces cross-site request risks.
- Harden the proxy. Add rate limiting, request size limits, and timeouts. Block unnecessary paths and methods.
- Isolate users and processes. Run the server as a dedicated non-root user. If multiple users share the server, separate them into containers or separate server instances rather than sharing one process.
- Limit extensions. Install only extensions you trust. Each extension runs with the server's privileges and can expose new endpoints.
- Log and monitor. Enable logging and watch for repeated authentication failures, unexpected restarts, and unusual kernel activity.
- Keep it patched. Track releases of Jupyter Server and any extensions, and update promptly.
A useful mental model
| Layer | What it protects | Typical control |
|---|---|---|
| Network | Who can reach the port | VPN, firewall, allowlist |
| Transport | Data in transit | TLS via reverse proxy |
| Authentication | Who can log in | Token or password |
| Authorization | What a logged-in user can do | Per-user instances, extension limits |
| Process | Blast radius of a compromise | Non-root user, containers |
| Operations | Detecting and responding | Logs, monitoring, patching |
Next step
Start from the server's own guidance on running a public server and on security, then map each item above to a concrete setting in your deployment. If you are migrating from the classic Notebook server, follow the migration guidance rather than copying old configuration blindly. The official documentation is at Jupyter Server documentation, and the project's source and issue tracker are at GitHub.
A practical test: from an outside network, confirm the server is unreachable without authentication, that HTTP redirects to HTTPS, and that a wrong token is rejected. Repeat this check after every configuration change.
How do I install and launch a bare Jupyter Server?
Install the jupyter-server package, then start it from a terminal with the jupyter server command. Because a "bare" server has no notebook or lab front end bundled in, you get the backend services and REST API without the usual browser interface — useful when you're building or testing your own front end, or when you want to inspect the API directly.
Install
pip install jupyter-server
Conda users can install from conda-forge instead:
conda install -c conda-forge jupyter-server
Installing into a virtual environment or a dedicated conda environment keeps the server's dependencies separate from other Jupyter front ends you may have installed.
Launch
jupyter server
The server prints a URL containing a token, something like http://localhost:8888/?token=.... Open that URL to reach the server's API landing page. If you only want the API and not a browser, you can copy the token and use it in requests, for example curl -H "Authorization: token <token>" http://localhost:8888/api/contents.
Useful options when launching:
--port 8889— run on a different port if 8888 is taken.--no-browser— don't try to open a browser automatically, handy on a remote machine.--ServerApp.token=''— disable token authentication. Only appropriate on a trusted single-user machine; never on a shared or public host.--allow-root— required if you're running as root, though running as root is discouraged.
What you actually get
A bare server exposes the core services and REST endpoints that Jupyter web applications build on — contents, kernels, sessions, terminals and the websocket kernel protocol. There is no notebook editor or file browser UI. To see something in a browser you either point an existing front end at it, or write against the API.
Choosing between this and a full front end
| Goal | Bare Jupyter Server | Notebook or JupyterLab |
|---|---|---|
| Call the REST API directly | Yes, this is the point | Possible but heavier |
| Develop a custom front end | Yes | Awkward |
| Edit and run notebooks in a browser | No UI included | Yes |
| Minimal dependency footprint | Smaller | Larger |
If your goal is simply to write and run notebooks interactively, install Project Jupyter's Notebook or JupyterLab instead — both run on top of Jupyter Server and give you the interface. Reach for the bare server when you're integrating, scripting or extending.
Next step: once it's running, fetch http://localhost:8888/api with your token to list the available endpoints, which is the quickest way to confirm the server is healthy and see what it offers.
How do I write a Jupyter Server extension?
Start with the Server Extensions section of the Jupyter Server documentation, since that is the page written specifically for the developer persona. Jupyter Server is the backend that provides core services, APIs and REST endpoints for Jupyter web applications, and extensions are how you add your own endpoints, services or behavior on top of it.
Jupyter Server documentation
What "writing an extension" actually means
You are building a Python package that Jupyter Server discovers and loads at startup. A minimal extension typically does three things:
- Declares one or more handler classes that respond to HTTP requests, using the REST API surfaces Jupyter Server already exposes.
- Registers those handlers through the extension's
_load_jupyter_server_extensionentry point so the server wires them into its routing. - Ships package metadata that advertises the extension, so
jupyter server extension enableand the server's config system can find it.
The documentation's developer track also covers architecture diagrams, depending on Jupyter Server as a library, the REST API, file save hooks, the contents API, and the WebSocket kernel wire protocol. Those pages matter once your extension needs to touch notebooks, files or kernels rather than just serve its own routes.
A concrete first project
Suppose you want an endpoint that reports which notebooks were modified in the last hour. You would write a handler subclassing Jupyter Server's base handler, return JSON from its get method, and register it under a path such as /myorg/recent. You then install the package into the same environment as the server and restart it. If the route does not appear, the usual causes are a missing entry point, the extension not being enabled, or the server running from a different environment than the one you installed into.
Choosing between extension styles
| Goal | Approach | Trade-off |
|---|---|---|
| Add HTTP endpoints or services | Server extension | Full control, but you own routing, auth and lifecycle |
| Change the notebook UI only | Frontend extension (for example in JupyterLab) | Lighter backend work, but tied to that frontend |
| Reuse existing notebook behavior | Depend on Jupyter Server as a library | Less code, but you inherit its version constraints |
Note that Jupyter Server replaced the Tornado Web Server in Jupyter Notebook, and the documentation points to a migration page for projects still built the old way. If you maintain an older Notebook server extension, plan that migration rather than copying old patterns.
Who should read which part
The docs split audiences deliberately: users for installation and launching, operators for deploying, configuring extensions and running a public server securely, and developers for extensions and the REST API. For extension work, stay in the developer section and treat the operator pages on security and logging as required reading before you expose anything beyond localhost.
Next step
Read the Server Extensions page end to end, then look at a small real extension to see the entry-point wiring in context. JupyterLab and NbClassic are both described as Jupyter Server extensions, so their source is a practical reference for structure, even though they are far larger than a first extension needs to be.
How does Jupyter Server differ from the Tornado Web Server in Jupyter Notebook?
Jupyter Server is the newer backend that provides the core services, APIs, and REST endpoints for Jupyter web applications. It replaces the Tornado Web Server that was embedded in the classic Jupyter Notebook, and Jupyter web applications are expected to migrate to it. In practice, that means the server layer is now a standalone project you run, configure, and extend, rather than a piece of the Notebook application itself.
What changes for you
The most visible difference is architectural. With the old Notebook server, the web server and the notebook application were tightly coupled. With Jupyter Server, the server is a separate foundation that frontends and extensions build on. JupyterLab, for example, runs on Jupyter Server, and NbClassic packages the classic notebook experience as a Jupyter Server extension.
That separation matters most when you want more than one interface or capability in the same server process. Extensions can add applications and services, such as a resource-usage monitor, a notebook job scheduler, or collaborative document support, without each one shipping its own web server.
Who notices the difference
- Users mostly see continuity: the same notebooks and interfaces, now served by a different backend. Problems usually appear as configuration or extension compatibility issues rather than day-to-day changes.
- Operators gain a single server to deploy and configure, but must handle extension management and the migration path from the Notebook server. Security, logging, and public-server configuration are documented separately for this reason.
- Developers get a documented REST API, server-extension framework, file save hooks, contents API, and WebSocket kernel protocols to build against, instead of modifying the Notebook server directly.
- Contributors work on one server library rather than the server code inside Notebook.
A practical next step
If you maintain a deployment or an extension that targets the old Notebook server, check whether it depends on Notebook-specific server internals. The migration guidance for moving from the Notebook server is the natural starting point, followed by the server-extension documentation if you are writing or updating extensions. For background on the surrounding projects, see Project Jupyter and JupyterLab documentation.
User reviews (0)