Developer Tools Azure

Polynote on Ubuntu 24.04 on Azure User Guide

| Product: Polynote on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Polynote on Ubuntu 24.04 on Azure using cloudimg 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, giving you live cell execution, rich result display, editor niceties such as autocomplete and parameter hints, and reproducible notebooks 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 sole 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, and for Polynote this matters more than usual. Polynote has no authentication of its own and, like any notebook kernel, 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, and 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; 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, will not even start until first boot has minted that per VM credential.

What is included:

  • Polynote 0.7.2 installed from the official release on OpenJDK 11, 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); it is never network exposed directly

  • nginx terminating TLS on :443, enforcing HTTP basic authentication and reverse proxying to Polynote, including the kernel WebSocket, with HSTS and sensible security headers

  • Port :80 returns 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, 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, hostname and 127.0.0.1); replace it with your own CA signed certificate for production

  • 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 seamless cloud integration and SSH key injection

  • 24/7 cloudimg 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 allowing 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; more memory allows larger data sets)

Step 1: Deploy from the Azure Portal

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

  2. Choose your subscription, resource group and region.

  3. Select a VM size (Standard_B2ms or larger) and provide your SSH public key for the azureuser account.

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

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

Step 2: Deploy from the Azure CLI

Deploy the image from the command line, restricting SSH to your management network. Replace the placeholder values with your own before running:

az vm create \
  --resource-group my-resource-group \
  --name polynote \
  --image <marketplace-image-urn> \
  --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>/.

Step 3: Retrieve your per instance admin credential

Access is protected by HTTP basic authentication. Each VM generates its own admin username and password on first boot, written to a root only file. Read it 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 only ever stores a one way bcrypt hash of the password, never the plain text.

The per VM polynote-credentials.txt file shown over SSH with the admin username and URL visible and the password value masked, generated uniquely on this VM's first boot

Step 4: Sign in to Polynote

Browse to https://<vm-ip>/. Because the certificate is self signed per VM, your browser will show 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 username and password from Step 3.

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

The Polynote web interface after signing in, showing the Polynote logo and Home view with the Notebooks panel on the left listing the Welcome to cloudimg Polynote notebook

Step 5: Open a notebook

Click Welcome to cloudimg 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.

The Welcome to cloudimg Polynote notebook open, showing a markdown heading and a Scala code cell defining a greeting string and computing 6 times 7

Step 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.

The Scala cell executed in Polynote, showing the inline output Out Tuple2 String Int equal to the greeting string and 42, with the kernel running

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

Step 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. It is where you start or kill the kernel and watch execution progress. Because each notebook has its own kernel, work in one notebook is isolated from another.

The Polynote Kernel panel on the right showing the running kernel with the notebook's defined symbols after the cell executed

Step 8: Verify the deployment

SSH to the VM as azureuser and confirm the services are running and 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.

systemctl reporting polynote and nginx active, and ss showing the notebook server bound to the loopback address on port 8192 only

Step 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, and the self test confirms an authenticated request succeeds while the server remains loopback only.

The polynote-selftest output reporting healthz 200, an unauthenticated request refused with 401, an authenticated request returning 200 for the Polynote UI, and the server bound 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

ss output showing nginx listening on ports 80 and 443 on all interfaces and Polynote listening on the loopback address on port 8192 only

Step 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 path 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.

Step 11: Baked version and configuration

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

cat /opt/polynote/CLOUDIMG_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. Access is protected by nginx HTTP basic authentication and a unique admin credential is generated on each VM's first boot. Only a one way bcrypt hash is stored; the plain password lives in the root only /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 auth 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 only reachable through the nginx TLS reverse proxy on :443. The notebook server will not start at all until first boot has minted the per VM credential.

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

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

Support

This image is backed by 24/7 cloudimg support with a guaranteed 24 hour response SLA. Contact support@cloudimg.co.uk for assistance. Polynote is open source software distributed under the Apache License 2.0 and is free; the cloudimg charge covers packaging, hardening, security patching, image maintenance and support.