Neko on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Neko on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Neko is an open source virtual browser: a real desktop browser runs inside a container on the VM, and its screen and audio are captured, encoded and streamed to viewers over WebRTC, the same low latency transport used by video calls. Anyone you give access to simply opens a URL and is looking at, and can take control of, a browser running somewhere else entirely. Nothing is installed on the viewer's machine.
Because the session is shared rather than personal, several people can watch the same browser at once and pass control between them, with a built in chat and an admin role that can lock the room, kick users and take control back. That makes it useful as a collaborative browsing space, as a disposable browser that keeps risky sites off your own machine and inside an isolated container, and as a way to reach an internal web application from anywhere without publishing that application to the internet.
The cloudimg image ships the free and open source, Apache-2.0 licensed Neko server, run the officially supported way as the upstream container pinned by image digest. This image uses the Firefox flavour, so the browser being streamed is Mozilla Firefox under the MPL-2.0 licence and the whole stack is open source. The container is captured into the VM, so your instance starts without downloading anything. Upstream ships fixed default passwords baked into the image (a user password and an admin password), which on a shared control remote browser would mean anyone who found your instance could drive it; this image never runs on them. A unique user password and a unique admin password are generated on the first boot of every VM, and the browser is held back from starting until that rotation has happened. Backed by 24/7 cloudimg support.
Neko is a trademark of its respective owner and Firefox is a trademark of the Mozilla Foundation. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by either. It ships the free and open source software, unmodified.

What is included:
- Neko v3.1.4 (the Apache-2.0 licensed virtual browser server), pinned by image digest
- Mozilla Firefox (MPL-2.0) as the streamed browser, inside the official upstream container
- Docker Engine, with the Neko web interface published to the loopback interface only and fronted by nginx on port
80 - WebRTC media multiplexed onto a single port, 59000, for both UDP and TCP, rather than a hundred port ephemeral range
neko.service,neko-firstboot.service,neko-postboot.serviceandnginx.serviceas systemd units, enabled and active on boot- A unique user password and a unique admin password generated per VM on first boot, never baked into the image
- The desktop preset to 1280x720 at 30 fps, a deliberate choice that a single node VM can encode in software
- Ubuntu 24.04 LTS base with the latest security patches applied at build time and unattended security upgrades enabled
Before you start: the network rules Neko needs
This is the one part of deploying Neko that is easy to get wrong, so it is worth reading before you launch.
Neko needs two kinds of traffic, and they are not the same:
| Port | Protocol | Carries | Required? |
|---|---|---|---|
80 |
TCP | The web interface and its WebSocket signalling | Yes |
59000 |
UDP | The WebRTC media stream, the primary path | Yes |
59000 |
TCP | The WebRTC media stream, fallback for networks that block UDP | Strongly recommended |
WebRTC media does not travel over HTTP, so it cannot be proxied through port 80. If you open only port 80, you will reach the login page and sign in successfully, and then the screen will simply stay black. That is the single most common Neko deployment problem and it is a firewall issue, not a fault in the image.
You must therefore allow inbound 80/tcp, 59000/udp and 59000/tcp in the network security group attached to your VM or its subnet. This guide shows how in Step 2. Restrict the source to your own address range wherever you can rather than leaving it open to the internet.
Prerequisites
- An Azure subscription with permission to create VMs and edit network security groups
- The Azure CLI installed and signed in, if you are deploying from the command line
- An SSH key pair for administrative access to the VM
- A modern browser on the viewing side (any current Firefox, Chrome, Edge or Safari supports WebRTC)
Sizing: what this really needs
Neko runs a full desktop, a browser and a software video encoder on the same machine, so it is genuinely CPU hungry. Upstream publishes its own guidance and it is worth taking seriously.
| Resolution | vCPU | RAM | Experience |
|---|---|---|---|
| 1024x576 at 30 fps | 2 | 2 GB | Not recommended |
| 1280x720 at 30 fps | 4 | 3 GB | Good |
| 1280x720 at 30 fps | 6 | 4 GB | Recommended |
| 1280x720 at 30 fps | 8 | 4 GB+ | Best |
Two practical points on top of that:
- Use a non burstable VM size. The recommended size for this image is
Standard_D4s_v5(4 vCPU). B series VMs are credit limited, and sustained video encoding will exhaust the credits and then throttle hard, at which point the stream becomes visibly choppy. B series is fine for trying the image out; it is not suitable for regular use. - Concurrency is not free. The encoding cost is per session, so one comfortable user at 720p30 is what 4 vCPU buys you. A handful of people watching the same session costs much less than the same number of independent sessions, because everyone shares one encoded stream. If you want more, add vCPU or lower the resolution rather than expecting it to scale on the same box.
The image ships preset to 1280x720 at 30 fps rather than the upstream container's own 1920x1080 at 60 fps default, because the latter is far heavier than most single node VMs can encode in software. An admin can change the resolution at runtime from the session settings.
Step 1: Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for Neko on Ubuntu 24.04 LTS by cloudimg and select Create.
- Choose your subscription, resource group and region.
- Set the VM size to Standard_D4s_v5 or larger (see the sizing table above).
- Provide an administrator username and SSH public key.
- On the Networking tab, allow inbound HTTP (80). The media ports are added in Step 2, because the portal's basic networking tab does not offer them.
- Review and create.
Step 2: Deploy from the Azure CLI
Run these on your own machine. Replace the resource group, name and region to suit.
az group create --name neko-rg --location eastus
az vm create \
--resource-group neko-rg \
--name neko-vm \
--image cloudimg:neko-ubuntu-24-04:default:latest \
--size Standard_D4s_v5 \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Now open the three ports Neko needs. This is the step that makes the media stream work:
az vm open-port --resource-group neko-rg --name neko-vm --port 80 --priority 1001
az network nsg rule create \
--resource-group neko-rg \
--nsg-name neko-vmNSG \
--name neko-webrtc-media \
--priority 1002 \
--direction Inbound --access Allow --protocol '*' \
--destination-port-ranges 59000 \
--description "Neko WebRTC media, UDP primary and TCP fallback"
To restrict access to your own network instead of the whole internet, add --source-address-prefixes <your.public.ip>/32 to both rules. On a shared control remote browser this is strongly recommended.
Step 3: Connect to your VM
ssh azureuser@<vm-ip>
Step 4: Confirm the services are running
systemctl is-active docker.service neko-firstboot.service neko.service neko-postboot.service nginx.service
Every line should read active. The Neko container itself is managed by a compose healthcheck:
sudo docker ps --format 'table {{.Image}}\t{{.Status}}'
You should see the pinned ghcr.io/m1k1o/neko/firefox:3.1.4 image reported as (healthy).
Step 5: Read the per instance credentials
Two passwords were generated for this VM alone on its first boot: one for the user role and one for the admin role. They are stored in a root only file.
sudo cat /root/neko-credentials.txt

The file records:
| Key | Meaning |
|---|---|
NEKO_USERNAME |
The display name for the standard role, cloudimg |
NEKO_USER_PASSWORD |
The per instance password for the user role |
NEKO_ADMINNAME |
The display name for the admin role, admin |
NEKO_ADMIN_PASSWORD |
The per instance password for the admin role |
WEB_URL |
The address to open in your browser |
PUBLIC_IP |
The address this VM advertises to WebRTC clients |
The file is 0600 root:root, so only root can read it:
sudo stat -c '%a %U:%G' /root/neko-credentials.txt
Step 6: Verify the security model
Upstream Neko ships with fixed default passwords baked into the container image, a user password of neko and an admin password of admin. This image never runs on them. You can prove that yourself.
Both upstream defaults are rejected:
curl -s -o /dev/null -w 'upstream default user password: HTTP %{http_code}\n' \
-X POST http://127.0.0.1/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"neko","password":"neko"}'
curl -s -o /dev/null -w 'upstream default admin password: HTTP %{http_code}\n' \
-X POST http://127.0.0.1/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}'
Both return 401.
An unauthenticated request to a protected endpoint is also rejected:
curl -s -o /dev/null -w 'no token: HTTP %{http_code}\n' http://127.0.0.1/api/whoami
This returns 401.
Your per instance password, by contrast, authenticates and returns a session token:
curl -s -X POST http://127.0.0.1/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"<NEKO_USERNAME>","password":"<NEKO_USER_PASSWORD>"}' \
| head -c 120
The image also holds the browser back until that rotation has happened. neko.service carries a ConditionPathExists on a bootstrap marker that only the first boot script creates after it has written the new passwords, so if first boot were ever to fail the browser would not start at all rather than starting on the published defaults:
grep ConditionPathExists /etc/systemd/system/neko.service
Finally, Neko's Prometheus metrics endpoint is unauthenticated upstream and its labels carry live session identifiers, so this image blocks it at the front door while keeping it available on the loopback interface for your own monitoring:
curl -s -o /dev/null -w 'metrics from outside: HTTP %{http_code}\n' http://127.0.0.1/metrics
This returns 404.
Step 7: Confirm the media path
The WebRTC media is multiplexed onto a single port for both protocols:
ss -lntu | grep 59000

The address the VM advertises to clients is resolved on each VM's own first boot, never baked into the image. You can see the value in use:
grep PUBLIC_IP /root/neko-credentials.txt 2>/dev/null || sudo grep PUBLIC_IP /root/neko-credentials.txt
The image ships a self test that exercises the whole path end to end, from authentication through to the capture pipeline and the media transport:
sudo /usr/local/sbin/neko-roundtrip.sh

Step 8: Open the session and sign in
Open http://<PUBLIC_IP>/ in your browser. You are asked for a display name and a password.

Enter any display name you like, and the password determines your role:
NEKO_USER_PASSWORDsigns you in as a user, who can watch the browser and request controlNEKO_ADMIN_PASSWORDsigns you in as an admin, who can additionally lock the room, kick users and take control back
Once connected, the streamed browser appears. This is a real Firefox running on the VM, not a screenshot or a rendered page.

If the interface loads but the screen stays black, the signalling worked and the media did not. That is almost always the firewall: check that 59000/udp and 59000/tcp are open inbound. See Step 2.
Step 9: Take control and browse
Control is explicit rather than automatic, so that two people cannot fight over the mouse. Click the keyboard or mouse icon in the bottom control bar to request control. As an admin you can take it outright.
Once you have control, the remote browser responds to your mouse and keyboard exactly as a local one would. Ctrl+L focuses the address bar, and you can type a URL and press Enter to navigate.
Everything you do happens inside the container on the VM, not on your own machine. Downloads land in the container, cookies belong to the container, and closing your tab leaves the browser running for anyone else in the session.
Step 10: Share the session
Anyone who can reach the VM and has a password can join the same session. The side panel shows a chat and the session events, so you can see who connected and who currently holds control.

Give collaborators the user password and keep the admin password to yourself. An admin can lock the room to stop new logins, and can take control back from any participant.
Step 11: Session settings
The settings tab adjusts your own view and, for admins, the room itself.

An admin can change the desktop resolution here at runtime. Lowering it is the quickest way to improve smoothness on a smaller VM; raising it costs CPU.
Step 12: Managing the service
sudo systemctl status neko.service --no-pager
Restart the browser session, which discards the running browser's state and starts a clean one:
sudo systemctl restart neko.service
View the server logs:
sudo docker logs --tail 40 neko-neko-1
Step 13: Changing the passwords
The passwords live in a root only environment file. To change one, edit the file and restart the service:
sudo sed -i 's/^NEKO_USER_PASSWORD=.*/NEKO_USER_PASSWORD=<new-password>/' /etc/neko/neko.env
sudo systemctl restart neko.service
Keep /root/neko-credentials.txt in step with any change you make, or simply treat the environment file as authoritative from then on.
Step 14: Use your own domain and HTTPS (production)
For anything beyond a trial, put a real hostname and a certificate in front of the web interface. Install a certificate with Certbot against the nginx site this image already ships, then reload nginx.
Two things to keep in mind:
- HTTPS covers port 80 traffic only. The WebRTC media on port 59000 is not HTTP and is not proxied; it continues to flow directly to the VM. Leave those rules in place.
- Browsers require a secure context for some features. Serving the interface over HTTPS is the right choice for any real deployment.
Step 15: Security recommendations
- Restrict the source addresses on both network security group rules to your own network. This is a browser other people can drive; do not leave it open to the internet.
- Treat the admin password as privileged. An admin can take control at any time and can see everything on the shared screen.
- Remember the session is shared. Anything you type into the remote browser, including passwords you enter on websites, is visible to everyone watching. Do not sign in to personal accounts in a shared session.
- Rotate the passwords if someone leaves the group, using Step 13.
- Keep the OS patched. Unattended security upgrades are enabled on this image by default.
Step 16: Support and Licensing
Neko is free and open source software under the Apache-2.0 licence. The streamed browser is Mozilla Firefox under the MPL-2.0 licence. The container also includes standard Debian encoding components, libx264 and the GStreamer "ugly" plugin set, which are licensed under the GPL-2.0-or-later and are used unmodified as distributed by Debian.
This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Neko project or the Mozilla Foundation. The Neko and Firefox names are used only to identify the software included.
For help with the image, contact cloudimg support, which is available 24/7. For questions about Neko itself, see the upstream project at github.com/m1k1o/neko.