ParaView Server on Ubuntu 24.04 on Azure User Guide
Overview
ParaView Server, pvserver, is the headless back end of ParaView: a data analysis and scientific visualisation server that a ParaView desktop client connects to for remote and parallel rendering. Instead of copying terabyte CFD, FEA or climate result sets down to a workstation, engineers run pvserver next to the data in the cloud and attach a lightweight client over the network. The heavy rendering happens server side, on this VM, and only the interactive client runs locally.
This image renders entirely headless. There is no GPU and no X server on the VM: pvserver, pvpython and pvbatch render through the system OSMesa software OpenGL library, so the appliance works on a plain Standard_B2s with no graphics hardware.
pvserver is secured by default. A stock pvserver listens on all interfaces with no authentication and will render whatever a connecting client sends, so an exposed pvserver is effectively unauthenticated remote access. This image closes that: pvserver is bound to loopback (127.0.0.1:11111) only, and a host firewall drops any traffic to port 11111 that does not arrive on the loopback interface. You reach it exactly as ParaView documents — over an SSH tunnel — so access is gated by the VM's own SSH authentication. There is no password or connect id to manage: reachability is the control.

What is included:
- ParaView Server 6.1.1 (official Kitware prebuilt Linux binary, BSD-3-Clause) at
/opt/paraview/current - Headless OSMesa software rendering, so
pvserverrenders with no GPU and no display pvserver.servicebound to127.0.0.1:11111, running as a dedicated non rootparaviewservice account, gated on a first boot markerparaview-firewall.service: an nftables table that drops every non loopback packet to port 11111- A small ready to render sample dataset baked into the image at
/var/lib/paraview/sample/wavelet.vti - A first boot service that resolves the VM address, writes
/root/paraview-server-info.txtand starts the server once per VM - A fully patched Ubuntu 24.04 LTS security baseline at capture time, with unattended security updates enabled
- 24/7 cloudimg support
Key facts: platform Ubuntu 24.04 LTS on Azure, default SSH user azureuser, install root /opt/paraview, server port 11111 (loopback only, reach over SSH tunnel), sample data /var/lib/paraview/sample/wavelet.vti.
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point; scale the VM size and OS disk to the datasets you will visualise. On your own workstation install the ParaView 6.1.1 desktop client (the same version as the server) from paraview.org/download — the client and server versions must match.
NSG inbound: allow only 22/tcp from your management network. Do not open port 11111 to the internet — the server is reached through the SSH tunnel, and this image binds it to loopback so it is not externally reachable in any case.
Step 1 — Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for ParaView Server by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) only. Then Review + create and Create. First boot initialisation takes a few seconds after the VM starts.
Step 2 — Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name paraview-server \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
Do not run az vm open-port for 11111 — the client reaches the server over the SSH tunnel in Step 6, not over an open port.
Step 3 — Connect to your VM
ssh azureuser@<vm-public-ip>
Look up the public IP at any time with az vm show -d -g <your-rg> -n paraview-server --query publicIps -o tsv.
Step 4 — Verify the ParaView Server stack
Two systemd services make up the appliance. Confirm both are active and that pvserver is bound to the loopback interface only:
systemctl is-active pvserver paraview-firewall
ss -tln | grep ':11111 '
Both lines read active, and the socket list shows pvserver on 127.0.0.1:11111 — never 0.0.0.0:
active
active
LISTEN 0 1 127.0.0.1:11111 0.0.0.0:*

Step 5 — Confirm the loopback only security posture
The image binds pvserver to loopback and adds a firewall so port 11111 is unreachable off the box. Inspect the firewall rule and confirm the port is not served on the VM's own non loopback address:
sudo nft list table inet cloudimg_paraview
PRIMARY_IP=$(hostname -I | awk '{print $1}')
timeout 4 bash -c "exec 3<>/dev/tcp/${PRIMARY_IP}/11111" 2>/dev/null \
&& echo "REACHABLE (unexpected)" || echo "port 11111 on ${PRIMARY_IP}: refused"
The firewall table drops any packet to port 11111 that does not arrive on lo, and the connection to the non loopback address is refused because pvserver listens on loopback only:
table inet cloudimg_paraview {
chain input {
type filter hook input priority -5; policy accept;
iif "lo" accept
tcp dport 11111 drop
}
}
port 11111 on 10.0.0.11: refused

Step 6 — Prove the headless render path
The image ships a self test that connects a pvpython client to the running pvserver, renders the sample dataset server side through OSMesa, and asserts the frame contains real content (not a blank image). Run it:
sudo /usr/local/sbin/paraview-render-check.sh
The check confirms the server is up on loopback, that the non loopback port is refused, and that both a standalone pvbatch render and a pvpython client to server render produce a real, non blank image:
render-check: pvserver bound loopback-only: LISTEN 0 1 127.0.0.1:11111 0.0.0.0:*
render-check: loopback 127.0.0.1:11111 accepts (server up)
render-check: non-loopback 10.0.0.11:11111 refused/filtered (secure)
RENDER_OK mode=local -> /tmp/pv-check-local.png
RENDER_OK mode=server -> /tmp/pv-check-server.png
render-check: pvserver active, loopback-only, headless render non-blank (standalone + client/server)
OK

Step 7 — Connect the ParaView desktop client over an SSH tunnel
pvserver is not exposed on the network, so you reach it with an SSH local forward. On your own workstation, open a tunnel that maps local port 11111 to the server's loopback port 11111:
ssh -N -L 11111:localhost:11111 azureuser@<vm-public-ip>
Leave that running. Then launch the ParaView 6.1.1 desktop client and connect to the server:
File > Connect... -> Add Server
Name: cloudimg-pvserver
Server Type: Client / Server
Host: localhost
Port: 11111
Configure -> Manual -> Save, then select the server and click Connect.
The client status bar shows it is connected to a server. Now open data on the server through the client's file browser (File > Open) — for example the shipped sample /var/lib/paraview/sample/wavelet.vti — apply a Contour filter and interact with the result. All rendering happens on the VM; only the interface runs locally.
Step 8 — The per VM instance info and sample dataset
Every VM writes an instance info file on first boot with its own connection instructions, and the sample dataset ships ready to open:
sudo cat /root/paraview-server-info.txt
ls -la /var/lib/paraview/sample/
cat /usr/share/doc/paraview-server/LICENSE | head -5
The info file records the SSH tunnel command and the loopback only posture; the sample directory holds wavelet.vti; and the shipped licence is the BSD-3-Clause text carrying the Kitware copyright:

Step 9 — Load your own data
Copy your result sets to the VM (they live on the server, next to pvserver), then open them through the connected client's file browser. From your workstation:
scp -r ./my-simulation-output azureuser@<vm-public-ip>:/var/lib/paraview/
For large or growing datasets, attach a dedicated Azure data disk, format it, mount it with a UUID keyed nofail fstab entry, and copy your data there — then point the client's file browser at the mount. ParaView reads the common scientific formats directly (VTK/VTU/VTI/VTP, ExodusII, CGNS, netCDF/CF, HDF5, XDMF and more).
Server Components
| Component | Version | Path |
|---|---|---|
| ParaView Server (pvserver) | 6.1.1 | /opt/paraview/current/bin/pvserver |
| pvpython / pvbatch (client + batch) | 6.1.1 | /opt/paraview/current/bin/ |
| OSMesa software OpenGL | distribution | system libOSMesa.so |
| Sample dataset | generated | /var/lib/paraview/sample/wavelet.vti |
Filesystem Layout
| Path | Description |
|---|---|
| / | Root filesystem |
| /opt/paraview | ParaView install (current symlinks the versioned directory) |
| /var/lib/paraview/sample/wavelet.vti | Shipped sample dataset |
| /usr/share/doc/paraview-server/LICENSE | BSD-3-Clause licence (Kitware) |
| /root/paraview-server-info.txt | Per VM instance info written at first boot |
| /etc/cloudimg-paraview-nft.conf | Loopback only firewall ruleset for port 11111 |
| /var/lib/cloudimg/paraview-server-firstboot.done | First boot bootstrap ready marker |
Managing the service
systemctl status pvserver --no-pager
sudo systemctl restart pvserver
journalctl -u pvserver -n 50 --no-pager
Security
pvserverruns as the non rootparaviewservice account with no shell and no sudo.- It binds
127.0.0.1:11111only; a host firewall (paraview-firewall.service) drops any non loopback packet to port 11111, enforced twice. - There is no default password or connect id; access is gated by the VM's SSH authentication through the tunnel.
- The
pvserverunit is gated on the first boot bootstrap ready marker, so it will not serve before first boot completes. - Keep
22/tcplimited to your management network. Do not open port 11111 to the internet.
Troubleshooting
The client cannot connect. Confirm the SSH tunnel from Step 7 is still running, and that systemctl is-active pvserver returns active on the VM. The client and server must both be ParaView 6.1.1 — a version mismatch is refused.
pvserver is not active. Inspect journalctl -u pvserver -n 100 --no-pager. The server only starts once the first boot marker exists at /var/lib/cloudimg/paraview-server-firstboot.done.
A render is blank. Confirm OSMesa is present with ldconfig -p | grep -i osmesa; the image ships libosmesa6. Re-run the self test in Step 6 — it asserts the rendered frame contains real content.
Support
For assistance, contact cloudimg support:
- Email: support@cloudimg.co.uk
- Response Time: 24/7 with a guaranteed 24 hour response SLA
- Website: https://cloudimg.co.uk