Server Configuration#

The Panel server can be launched either from the commandline (using panel serve) or programmatically (using panel.serve()). In this guide we will discover how to run and configure server instances using these two options.

Launching a server on the commandline#

Once the app is ready for deployment it can be served using the Bokeh server. For a detailed breakdown of the design and functionality of Bokeh server, see the Bokeh documentation. The most important thing to know is that Panel (and Bokeh) provide a CLI command to serve a Python script, app directory, or Jupyter notebook containing a Bokeh or Panel app. To launch a server using the CLI, simply run:

panel serve app.ipynb

Alternatively you can also list multiple apps:

panel serve app1.py app2.ipynb

or even serve a number of apps at once:

panel serve apps/*.py

For development it can be particularly helpful to use the --autoreload option to panel serve as that will automatically reload the page whenever the application code or any of its imports change.

The panel serve command has the following options:

positional arguments:
  DIRECTORY-OR-SCRIPT   The app directories or scripts or notebooks to serve
                        (serve empty document if not specified)

optional arguments:
  -h, --help            show this help message and exit
  --port PORT           Port to listen on
  --address ADDRESS     Address to listen on
  --log-level LOG-LEVEL
                        One of: trace, debug, info, warning, error or critical
  --log-format LOG-FORMAT
                        A standard Python logging format string (default:
                        '%(asctime)s %(message)s')
  --log-file LOG-FILE   A filename to write logs to, or None to write to the
                        standard stream (default: None)
  --args ...            Any command line arguments remaining are passed on to
                        the application handler
  --show                Open server app(s) in a browser
  --allow-websocket-origin HOST[:PORT]
                        Public hostnames which may connect to the Bokeh
                        websocket
  --prefix PREFIX       URL prefix for Bokeh server URLs
  --keep-alive MILLISECONDS
                        How often to send a keep-alive ping to clients, 0 to
                        disable.
  --check-unused-sessions MILLISECONDS
                        How often to check for unused sessions
  --unused-session-lifetime MILLISECONDS
                        How long unused sessions last
  --stats-log-frequency MILLISECONDS
                        How often to log stats
  --mem-log-frequency MILLISECONDS
                        How often to log memory usage information
  --use-xheaders        Prefer X-headers for IP/protocol information
  --auth-module AUTH_MODULE
                        Absolute path to a Python module that implements auth hooks
  --enable-xsrf-cookies
                        Whether to enable Tornado support for XSRF cookies.
                        All PUT, POST, or DELETE handlers must be properly
                        instrumented when this setting is enabled.
  --exclude-headers EXCLUDE_HEADERS [EXCLUDE_HEADERS ...]
                        A list of request headers to exclude from the session
                        context (by default all headers are included).
  --exclude-cookies EXCLUDE_COOKIES [EXCLUDE_COOKIES ...]
                        A list of request cookies to exclude from the session
                        context (by default all cookies are included).
  --include-headers INCLUDE_HEADERS [INCLUDE_HEADERS ...]
                        A list of request headers to make available in the
                        session context (by default all headers are included).
  --include-cookies INCLUDE_COOKIES [INCLUDE_COOKIES ...]
                        A list of request cookies to make available in the
                        session context (by default all cookies are included).
  --session-ids MODE    One of: unsigned, signed, or external-signed
  --index INDEX         Path to a template to use for the site index or
                        an app to serve at the root.
  --disable-index       Do not use the default index on the root path
  --disable-index-redirect
                        Do not redirect to running app from root path
  --num-procs N         Number of worker processes for an app. Using 0 will
                        autodetect number of cores (defaults to 1)
  --num-threads N       Number of threads to launch in a ThreadPoolExecutor which
                        Panel will dispatch events to for concurrent execution on
                        separate cores (defaults to None).
  --warm                Whether to execute scripts on startup to warm up the server.
  --autoreload
                        Whether to automatically reload user sessions when the application or any of its imports change.
  --static-dirs KEY=VALUE [KEY=VALUE ...]
                        Static directories to serve specified as key=value
                        pairs mapping from URL route to static file directory.

  --dev [FILES-TO-WATCH [FILES-TO-WATCH ...]]
                        Enable live reloading during app development.By
                        default it watches all *.py *.html *.css *.yaml
                        filesin the app directory tree. Additional files can
                        be passedas arguments. NOTE: This setting only works
                        with a single app.It also restricts the number of
                        processes to 1.
  --session-token-expiration N
                        Duration in seconds that a new session token is valid
                        for session creation. After the expiry time has elapsed,
                        the token will not be able create a new session
                        (defaults to seconds).
  --websocket-max-message-size BYTES
                        Set the Tornado websocket_max_message_size value
                        (defaults to 20MB) NOTE: This setting has effect ONLY
                        for Tornado>=4.5
  --websocket-compression-level LEVEL
                        Set the Tornado WebSocket compression_level
  --websocket-compression-mem-level LEVEL
                        Set the Tornado WebSocket compression mem_level
  --oauth-provider OAUTH_PROVIDER
                        The OAuth2 provider to use.
  --oauth-key OAUTH_KEY
                        The OAuth2 key to use
  --oauth-secret OAUTH_SECRET
                        The OAuth2 secret to use
  --oauth-redirect-uri OAUTH_REDIRECT_URI
                        The OAuth2 redirect URI
  --oauth-extra-params OAUTH_EXTRA_PARAMS
                        Additional parameters to use.
  --oauth-jwt-user OAUTH_JWT_USER
                        The key in the ID JWT token to consider the user.
  --oauth-encryption-key OAUTH_ENCRYPTION_KEY
                        A random string used to encode the user information.
  --rest-provider REST_PROVIDER
                        The interface to use to serve REST API
  --rest-endpoint REST_ENDPOINT
                        Endpoint to store REST API on.
  --rest-session-info
                        Whether to serve session info on the REST API
  --session-history SESSION_HISTORY
                        The length of the session history to record.
  --setup
                        Path to a setup script to run before server starts, e.g. to cache data or set up scheduled tasks.
  --liveness
                        Whether to add an endpoint to confirm liveness of the server and optionally various endpoints
                        (defaults to /liveness but endpoint can be controlled with --liveness-endpoint)
  --liveness-endpoint
                        The endpoint to serve the liveness API at.

To turn a notebook into a deployable app simply append .servable() to one or more Panel objects, which will add the app to Bokeh’s curdoc, ensuring it can be discovered by Bokeh server on deployment. In this way it is trivial to build dashboards that can be used interactively in a notebook and then seamlessly deployed on Bokeh server.

When called on a notebook, panel serve first converts it to a python script using nbconvert.PythonExporter(), albeit with IPython magics stripped out. This means that non-code cells, such as raw cells, are entirely handled by nbconvert and may modify the served app.

Launching a server dynamically#

The CLI panel serve command described below is usually the best approach for deploying applications. However when working on the REPL or embedding a Panel/Bokeh server in another application it is sometimes useful to dynamically launch a server, either using the .show method or using the pn.serve function.

Previewing an application#

Working from the command line will not automatically display rich representations inline as in a notebook, but you can still interact with your Panel components if you start a Bokeh server instance and open a separate browser window using the show method. The method has the following arguments:

port: int (optional)
   Allows specifying a specific port (default=0 chooses an arbitrary open port)
websocket_origin: str or list(str) (optional)
   A list of hosts that can connect to the websocket.
   This is typically required when embedding a server app in
   an external-facing web site.
   If None, "localhost" is used.
threaded: boolean (optional, default=False)
   Whether to launch the Server on a separate thread, allowing
   interactive use.
title : str
   A string title to give the Document (if served as an app)
**kwargs : dict
   Additional keyword arguments passed to the bokeh.server.server.Server instance.

To work with an app completely interactively you can set threaded=True which will launch the server on a separate thread and let you interactively play with the app.

The .show call will return either a Bokeh server instance (if threaded=False) or a StoppableThread instance (if threaded=True) which both provide a stop method to stop the server instance.

Serving multiple apps#

If you want to serve more than one app on a single server you can use the pn.serve function. By supplying a dictionary where the keys represent the URL slugs and the values must be either Panel objects or functions returning Panel objects you can easily launch a server with a number of apps, e.g.:

import panel as pn
pn.serve({
    'markdown': '# This is a Panel app',
    'json': pn.pane.JSON({'abc': 123})
})

Note that when you serve an object directly all sessions will share the same state, i.e. the parameters of all components will be synced across sessions such that the change in a widget by one user will affect all other users. Therefore you will usually want to wrap your app in a function, ensuring that each user gets a new instance of the application:


def markdown_app():
    return '# This is a Panel app'

def json_app():
    return pn.pane.JSON({'abc': 123})

pn.serve({
    'markdown': markdown_app,
    'json': json_app
})

You can customize the HTML title of each application by supplying a dictionary where the keys represent the URL slugs and the values represent the titles, e.g.:

pn.serve({
    'markdown': '# This is a Panel app',
    'json': pn.pane.JSON({'abc': 123})
}, title={'markdown': 'A Markdown App', 'json': 'A JSON App'}
)

The pn.serve accepts a number of arguments:

panel: Viewable, function or {str: Viewable or function}
  A Panel object, a function returning a Panel object or a
  dictionary mapping from the URL slug to either.
port: int (optional, default=0)
  Allows specifying a specific port
address: str
  The address the server should listen on for HTTP requests.
websocket_origin: str or list(str) (optional)
  A list of hosts that can connect to the websocket.

  This is typically required when embedding a server app in
  an external web site.

  If None, "localhost" is used.
loop: tornado.ioloop.IOLoop (optional, default=IOLoop.current())
  The tornado IOLoop to run the Server on
show: boolean (optional, default=False)
  Whether to open the server in a new browser tab on start
start: boolean(optional, default=False)
  Whether to start the Server
title: str or {str: str} (optional, default=None)
  An HTML title for the application or a dictionary mapping
  from the URL slug to a customized title
verbose: boolean (optional, default=True)
  Whether to print the address and port
location: boolean or panel.io.location.Location
  Whether to create a Location component to observe and
  set the URL location.
kwargs: dict
  Additional keyword arguments to pass to Server instance

Static file hosting#

Whether you’re launching your application using panel serve from the commandline or using pn.serve in a script you can also serve static files. When using panel serve you can use the --static-dirs argument to specify a list of static directories to serve along with their routes, e.g.:

panel serve some_script.py --static-dirs assets=./assets

This will serve the ./assets directory on the servers /assets route. Note however that the /static route is reserved internally by Panel.

Similarly when using pn.serve or panel_obj.show the static routes may be defined as a dictionary, e.g. the equivalent to the example would be:

pn.serve(panel_obj, static_dirs={'assets': './assets'})