Neko is an open-source virtual browser platform that runs inside Docker and streams an interactive browser session to multiple users over WebRTC, with synchronized audio/video and admin-controlled input handoff. This guide deploys Neko using Docker Compose with Traefik handling automatic HTTPS, and persistent Firefox profile storage. By the end, you'll have a shared virtual browser session running securely at your domain.
Set Up the Directory Structure
1. Create the project directory with a Firefox profile subdirectory:
$ mkdir -p ~/neko/profile
$ cd ~/neko
2. Create the environment file:
$ nano .env
DOMAIN=neko.example.com
LETSENCRYPT_EMAIL=admin@example.com
NEKO_ADMIN_PASSWORD=StrongAdminPassword123
NEKO_USER_PASSWORD=StrongUserPassword456
3. Set ownership on the profile directory, Neko runs as UID 1000:
$ sudo chown -R 1000:1000 ~/neko/profile
Deploy with Docker Compose
1. Create the Docker Compose manifest:
$ nano docker-compose.yaml
services:
traefik:
image: traefik:v3.6
container_name: traefik
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
restart: unless-stopped
neko:
image: ghcr.io/m1k1o/neko/firefox:3
container_name: neko
shm_size: "2gb"
expose:
- "8080"
ports:
- "52000-52100:52000-52100/udp"
volumes:
- "./profile:/home/neko/.mozilla/firefox/profile.default"
environment:
NEKO_MEMBER_PROVIDER: "multiuser"
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "${NEKO_USER_PASSWORD}"
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "${NEKO_ADMIN_PASSWORD}"
NEKO_SERVER_PROXY: "true"
NEKO_DESKTOP_SCREEN: "1280x720@30"
NEKO_WEBRTC_EPR: "52000-52100"
NEKO_WEBRTC_ICELITE: "true"
labels:
- "traefik.enable=true"
- "traefik.http.routers.neko.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.neko.entrypoints=websecure"
- "traefik.http.routers.neko.tls.certresolver=letsencrypt"
- "traefik.http.services.neko.loadbalancer.server.port=8080"
restart: unless-stopped
volumes:
letsencrypt:
The shm_size: "2gb" allocation is required, Firefox rendering crashes or freezes without enough shared memory. NEKO_WEBRTC_EPR opens the UDP port range WebRTC media travels over; NEKO_WEBRTC_ICELITE suits servers with a public IP and direct inbound UDP.
2. Start the services:
$ docker compose up -d
3. Verify both services are running:
$ docker compose ps
$ docker compose logs
Access Neko
- Open
https://neko.example.com. - Enter a display name and the admin password from
.env, then click CONNECT. - The Firefox window loads in the center with a control bar below. Connected users appear as avatars; a green badge marks whoever holds control.
- The side panel has Chat (activity log) and Settings (scroll sensitivity, keyboard layout, autoplay).
Run a Collaborative Session
- Share the URL and the user password (not the admin one) with participants.
- Each participant enters a display name + password and clicks CONNECT — their avatar appears at the bottom.
- Navigate to any URL in the address bar. WebRTC streams it to everyone with minimal delay.
- Right-click a user's avatar to Give Controls, Kick, or Ban IP (kick/ban are admin-only).
Next Steps
Neko is running and streaming a shared browser session over HTTPS. From here you can:
- Swap the Firefox image for Chromium or a custom browser image
- Add a TURN server for participants behind restrictive NATs
- Scale to multiple rooms by running additional Neko containers on different subdomains
For the full guide with additional tips, visit the original article on Vultr Docs.
Top comments (1)
Running full browser instances, even containerized like Neko, always brings up an immediate question about resource consumption. We've seen firsthand how quickly CPU and memory can spike when dealing with multiple concurrent interactive sessions, especially if users are navigating complex web applications within those virtual browsers. Getting that right, without over-provisioning or leading to a sluggish user experience, is a constant balancing act in a production environment.
The appeal of a self-hosted solution for specific use cases is clear, offering full control over the stack. However, that control comes with significant operational overhead. Beyond just getting Neko deployed, the ongoing effort involves patching the underlying browser engine, managing Docker resource limits per session, and continually optimizing for low-latency streaming. For an interactive platform, network conditions and server-side rendering performance become crucial bottlenecks that demand constant attention to ensure a responsive feel for end-users.
One key aspect we always consider with systems like this in a multi-tenant SaaS context is robust isolation between user sessions. Ensuring that one user's browser activity, or potential resource hogs, doesn't impact another's is paramount. This often means carefully architecting how instances are spun up and torn down, how resource limits are enforced, and how to prevent any state leakage. It's a powerful tool, but the operational discipline required to run it smoothly at scale shouldn't be underestimated.