Deployment guide

Polynote

Overview

This guide covers deploying and configuring Polynote on Ubuntu 24.04 on Azure, from SecureAnyCloud Azure Marketplace images. Polynote is an open source, polyglot notebook environment created at Netflix for interactive data science and analytics.

It pairs a modern, IDE-like web interface with first-class support for Scala alongside Python and SQL. You get live cell execution, rich result display, and editor features such as autocomplete and parameter hints. Notebooks are reproducible and stored as readable files on disk.

The image installs the official pinned Polynote 0.7.2 release on OpenJDK 11 and runs it under systemd as the unprivileged polynote system user, bound to loopback only (127.0.0.1:8192). nginx is the only network-facing surface. It terminates TLS on port 443, enforces HTTP basic authentication on every request (including the kernel WebSocket), and reverse proxies to Polynote. Port 80 redirects to HTTPS.

Secure by default, which matters more than usual for Polynote. Polynote has no authentication of its own. Like any notebook kernel, it deliberately allows arbitrary code execution, so an unprotected Polynote reachable over the network is a serious remote code execution risk. This image never exposes it directly.

Polynote is bound to loopback and fronted by nginx basic authentication. A unique administrator credential is generated on each virtual machine's first boot. Only a one-way bcrypt hash of the password is written to the server, and the plain password is placed in a root-only file for the administrator to read. There are no shared or default credentials, and nothing usable is baked into the image.

As a further safeguard, the notebook server, which is the code execution engine, does not start until first boot has created that per-VM credential.

What you get:

  • Polynote 0.7.2, installed from the official release on OpenJDK 11 and run under systemd as the unprivileged polynote system user
  • The Scala kernel dependencies pre-warmed into the image so your first cell runs immediately, and a Python kernel environment (jep, numpy, pandas) for Python cells
  • Polynote bound to loopback only (127.0.0.1:8192), never exposed to the network directly
  • nginx terminating TLS on :443, enforcing HTTP basic authentication and reverse proxying to Polynote, including the kernel WebSocket, with HSTS and standard security headers
  • Port :80 returning a 301 redirect to HTTPS for every path except an unauthenticated /healthz endpoint (HTTP 200) for load balancer probes
  • A unique admin credential generated per VM on first boot. Only the one-way bcrypt hash is stored, and the plain password lands in a root-only file
  • A self-signed TLS certificate regenerated per VM on first boot. Its Subject Alternative Names include the VM public IP, the hostname and 127.0.0.1. For production, replace it with your own CA-signed certificate
  • A starter welcome notebook, so you land on a working Scala example
  • A built-in self-test at /usr/local/bin/polynote-selftest that proves the authenticated notebook UI and the loopback-only bind end to end over TLS
  • Ubuntu 24.04 LTS base with the latest security patches applied at build time
  • Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA

Prerequisites

  • An Azure subscription with permission to deploy virtual machines
  • An SSH key pair for administrative access to the VM as the azureuser account
  • A Network Security Group that allows inbound TCP 443 (HTTPS) and 80 (redirect) from the networks that should reach the service, and 22 (SSH) from your management network only
  • A recommended size of Standard_B2ms or larger. Polynote runs a JVM notebook server plus one or more kernels, and more memory allows larger data sets
1

Deploy from the Azure Portal

Find the Polynote on Ubuntu 24.04 LTS image in the Azure Marketplace and select Create.

Choose your subscription, resource group and region. Select a VM size (Standard_B2ms or larger) and provide your SSH public key for the azureuser account.

On the Networking tab, allow inbound 443 and 80 from your users, and restrict 22 to your management network.

Review and create the VM. When it is running, browse to https://<your-public-ip>/.

2

Deploy from the Azure CLI

Deploy the image from the command line and restrict SSH to your management network. Replace the example values with your own before you run the commands:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:polynote-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-resource-group \
  --name polynote \
  --image sac1647283583153:polynote-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard
# Allow the web UI from your users and SSH from your management network only
az vm open-port --resource-group my-resource-group --name polynote --port 443 --priority 1001
az network nsg rule create --resource-group my-resource-group --nsg-name polynoteNSG \
  --name allow-ssh --priority 1002 --destination-port-ranges 22 \
  --source-address-prefixes <your-mgmt-cidr> --access Allow --protocol Tcp

When the VM is running, browse to https://<public-ip>/.

3

Retrieve your per-instance admin credential

HTTP basic authentication protects access. Each VM generates its own admin user name and password on first boot and writes them to a root-only file. Read the file over SSH:

sudo cat /root/polynote-credentials.txt

The file contains the POLYNOTE_USER, POLYNOTE_PASSWORD and POLYNOTE_URL for this specific VM. Keep it secret. The server stores only a one-way bcrypt hash of the password, never the plain text.

4

Sign in to Polynote

Browse to https://<vm-ip>/. The certificate is self-signed per VM, so your browser shows a certificate warning the first time. Accept it to proceed, or install the per-VM certificate, or place a CA-signed certificate in front, as covered in Step 10.

Your browser then prompts for the basic authentication user name and password from Step 3.

Polynote opens on its home view, which lists your notebooks in the left panel. The image ships a Welcome to SecureAnyCloud Polynote notebook, so you have a working example to run immediately.

5

Open a notebook

Click Welcome to SecureAnyCloud Polynote in the Notebooks panel to open it. It contains a short description and a Scala code cell that binds two values and returns them as a tuple.

The editor gives you syntax highlighting, autocomplete and inline results.

6

Run a cell on the kernel

Press Shift+Enter in the cell, or click Run all cells in the toolbar. Polynote starts the Scala kernel (the green dot in the Kernel panel turns on) and executes the cell.

The computed result appears inline beneath the code: a Tuple2[String, Int] whose second element is 42. This is Polynote running your code live on a real kernel and returning the value.

Create your own notebook with the + button in the Notebooks panel, choose Scala, Python or SQL for each cell, and start exploring your data. Notebooks are saved as readable files under /var/lib/polynote/notebooks on the VM.

7

Inspect the kernel and symbols

The Kernel panel on the right shows the running kernel, the symbols your cells have defined and any active tasks. Use it to start or kill the kernel and to watch execution progress.

Each notebook has its own kernel, so work in one notebook is isolated from another.

8

Verify the deployment

Connect to the VM over SSH as azureuser. Confirm that the services are running and that Polynote is bound to loopback only:

systemctl is-active polynote nginx
sudo ss -tlnp | grep 8192

Both services report active, and Polynote listens on the loopback address on port 8192 only. nginx is the only component exposed on :80 and :443.

9

TLS, redirect and the authentication gate

nginx terminates TLS on port 443 and redirects plain HTTP on port 80 to HTTPS. The built-in self-test reads this VM's credential and proves the full path over TLS. The health probe answers, an unauthenticated request is refused, and an authenticated request loads the Polynote UI, while the notebook server stays bound to loopback only:

curl -s -o /dev/null -w 'port 80 -> HTTP %{http_code}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'healthz -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'no creds -> HTTP %{http_code}\n' https://127.0.0.1/
sudo /usr/local/bin/polynote-selftest

Port 80 returns 301, and the health endpoint returns 200. An unauthenticated request to the notebook UI is refused with 401. The self-test confirms that an authenticated request succeeds while the server remains loopback-only.

Confirm the network exposure directly. nginx owns :80 and :443, while Polynote is loopback-only on :8192:

sudo ss -tlnH | awk '{print $4}' | grep -E ':(80|443|8192)$' | sort -u
10

Replace the certificate for production

The per-VM certificate is self-signed, so browsers warn on first use. For a public deployment, put a real certificate in front. The simplest approach is to point a DNS name at the VM and obtain a free certificate with Certbot:

# Point https://<your-domain> at this VM first, then:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

Alternatively, terminate TLS at an Azure Application Gateway or a load balancer in front of the VM, and forward to port 443.

11

Baked version and configuration

The VM records the baked Polynote and Java versions. The notebook server configuration, including the loopback bind and the notebook storage location, lives in /var/lib/polynote/config.yml. Print the recorded versions:

cat /opt/polynote/SAC_VERSION

To raise the kernel memory for larger workloads, edit the kernel.jvmArgs value in /var/lib/polynote/config.yml. Then restart the service with sudo systemctl restart polynote.

Security notes

No default login. nginx HTTP basic authentication protects access, and each VM generates a unique admin credential on its first boot. Only a one-way bcrypt hash is stored. The plain password lives in the root-only file /root/polynote-credentials.txt.

Arbitrary code execution by design. A notebook kernel runs whatever code you give it. Never expose Polynote directly. Keep it behind the nginx basic authentication gate over TLS, restrict 443 to the networks that need it, and treat access to the notebook as access to a shell on the VM.

Loopback-only application. Polynote binds to 127.0.0.1:8192 and is reachable only through the nginx TLS reverse proxy on :443. The notebook server does not start at all until first boot has created the per-VM credential.

Restrict access. Allow 443 only from the networks that need it, and keep 22 restricted to your management network. For production, replace the self-signed certificate with a CA-signed one.

Rotate the credential by regenerating the nginx htpasswd entry (sudo htpasswd -B /etc/nginx/polynote.htpasswd admin) and reloading nginx. Alternatively, place your own identity-aware proxy in front.

Support

This image is backed by 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA. Contact sales@secureanycloud.com for assistance.

Polynote is open source software distributed under the Apache License 2.0 and is free. The SecureAnyCloud charge covers packaging, hardening, security patching, image maintenance and support.

Deploy on Azure

Launch Polynote on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure