Server Deployment

Panel is built on top of Bokeh, which provides a powerful Tornado based web-server to communicate between Python and the browser. The bokeh server makes it possible to share the app or dashboard you have built locally, your own web server or using any of the numerous cloud providers. In this guide we will go through the details of deploying an app on a local system or cloud provider step by step.

The server

The Bokeh server is built on Tornado, which handles all of the communication between the browser and the backend. Whenever a user accesses the app or dashboard in a browser a new session is created which executes the app code and creates a new Document containing the models served to the browser where they are rendered by BokehJS.

Accessing request arguments

When a user accesses the Panel application via the browser they can optionally provide additional arguments in the URL. For example the query string ?N=10 will result in the following argument will be available on pn.state.session_args: {'N': [b'10']}. Such arguments may be used to customize the application.


As was covered in Deploy and Export guide a Panel app, either in a notebook or a Python script, can be annotated with .servable() and then launched from the commandline using panel serve. This launches a Tornado server on a specific port (defaulting to 5006) which you can access locally at https://localhost:{PORT}. This is a good option for simple deployments on a local network.

However many deployment scenarios have additional requirements around authentication, scaling, and uptime.


In some scenarios a standalone bokeh server may be running on remote host. In such cases, SSH can be used to “tunnel” to the server. In the simplest scenario, the Bokeh server will run on one host and will be accessed from another location, e.g., a laptop, with no intermediary machines.

Run the server as usual on the remote host:

Next, issue the following command on the local machine to establish an SSH tunnel to the remote host:

ssh -NfL localhost:5006:localhost:5006

Replace user with your username on the remote host and with the hostname/IP address of the system hosting the Bokeh server. You may be prompted for login credentials for the remote system. After the connection is set up you will be able to navigate to localhost:5006 as though the Bokeh server were running on the local machine.

The second, slightly more complicated case occurs when there is a gateway between the server and the local machine. In that situation a reverse tunnel must be established from the server to the gateway. Additionally the tunnel from the local machine will also point to the gateway.

Issue the following commands on the remote host where the Bokeh server will run:

nohup bokeh server &
ssh -NfR 5006:localhost:5006

Replace user with your username on the gateway and with the hostname/IP address of the gateway. You may be prompted for login credentials for the gateway.

Now set up the other half of the tunnel, from the local machine to the gateway. On the local machine:

ssh -NfL localhost:5006:localhost:5006

Again, replace user with your username on the gateway and with the hostname/IP address of the gateway. You should now be able to access the Bokeh server from the local machine by navigating to localhost:5006 on the local machine, as if the Bokeh server were running on the local machine. You can even set up client connections from a Jupyter notebook running on the local machine.

Reverse proxy

If the goal is to serve an web application to the general Internet, it is often desirable to host the application on an internal network, and proxy connections to it through some dedicated HTTP server. For some basic configurations to set up a Bokeh server behind some common reverse proxies, including Nginx and Apache, refer to the Bokeh documentation.

Cloud Deployments

If you do not want to maintain your own web server and/or set up complex reverse proxies various cloud providers make it relatively simple to quickly deploy arbitrary apps on their system. In this section we will go through step-by-step to set up deployments on some of these providers.


Binder allows you to create custom computing environments that can be shared and used by many remote users. MyBinder is a public, free hosting option, with limited compute and memory resources, which will allow you to deploy your simple app quickly and easily.

Here we will take you through the configuration to quickly set up a GitHub repository with notebooks containing Panel apps for deployment on As an example refer to the Clifford demo repository.

  1. Create a GitHub repository and add the notebook or script you want to serve (in the example repository this is the clifford.ipynb file)

  2. Add an environment.yml which declares a conda environment with the dependencies required to run the app (refer to the conda documentation to see how to declare your dependencies). Add jupyter_panel_proxy as a dependency by adding either conda-forge or pyviz to the channel list:

- pyviz

- jupyter-panel-proxy
  1. Go to, enter the URL of your GitHub repository and hit Launch

  2. will give you a link to the deployment, e.g. for the example app it is To visit the app simply append ??urlpath=/panel/clifford where you should replace clifford with the name of the notebook or script you are serving.


Heroku makes deployment of arbitrary apps including Panel apps and dashboards very easy and provides a free tier to get you started. This makes it a great starting point for users not too familiar with web development and deployment.

To get started working with Heroku signup for a free account and download and install the CLI. Once you are set up follow the instructions to log into the CLI.

  1. Create a new Git repo (or to follow along clone the minimal-heroku-demo GitHub repo)

  2. Add a Jupyter notebook or Python script which declares a Panel app or dashboard to the repository.

  3. Define a requirements.txt containing all the requirements for your app (including Panel itself). For the sample app the requirements are as minimal as:

  1. Define a Procfile which declares the command Heroku should run to serve the app. In the sample app the following command serves the iris_kmeans.ipynb example. The websocket origin should match the name of the app on Heroku which you will declare in the next step:
web: panel serve --address="" --port=$PORT iris_kmeans.ipynb
  1. Create a Heroku app using the CLI ensuring that the name matches the URL we declared in the previous step:
heroku create app-name
  1. Push the app to heroku and wait until it is deployed.

  2. Visit the app at

Once you have deployed the app you might find that if your app is visited by more than one user at a time it will become unresponsive. In this case you can use the Heroku CLI to scale your deployment.

Anaconda Enterprise 5 (AE5)

All live examples in the Panel documentation are served on AE5, to see further examples deployed there see and for detailed instructions follow the developer guide.

Other Cloud Providers

Panel can be used with just about any cloud provider that can launch a Python process, including Amazon Web Services (AWS), Google Cloud Platform (GCP), Azure, and DigitalOcean. The Panel developers will add documentation for these services as they encounter them in their own work, but we would greatly appreciate step-by-step instructions from users working on each of these systems.

In [ ]:

Right click to download this notebook from GitHub.