Kali Linux in the Browser with VNC + noVNC (No Nginx)
AWS EC2 ➜ XFCE ➜ VNC ➜ noVNC ➜ HTTPS (self‑signed or Let's Encrypt standalone). Copy‑paste friendly.
Prerequisites
- AWS account and an EC2 instance from a Kali Linux AMI (t2.medium recommended for smoother UI).
- SSH access (PuTTY on Windows or OpenSSH).
- Basic Linux shell familiarity.
1) Create/Update the Security Group
Allow access only from your workstation where possible.
- TCP 22 — SSH (source: your IP)
- TCP 6080 — noVNC (source: your IP; use 0.0.0.0/0 only while testing)
- TCP 5901 — optional native VNC (source: your IP)
- TCP 80 — required only for Let's Encrypt standalone issuance
2) Install XFCE Desktop & TightVNC
Update packages, install a lightweight desktop, then initialize VNC and set a password. Display :1 maps to TCP 5901.
sudo apt update && sudo apt -y upgrade
sudo apt -y install xfce4 xfce4-goodies tightvncserver
# First run: create password and start display :1
vncserver :1
# If you need to stop and retry later:
vncserver -kill :1
3) Configure XFCE as the VNC Session
Create/replace ~/.vnc/xstartup so VNC launches XFCE instead of the minimal defaults.
mkdir -p ~/.vnc
cat > ~/.vnc/xstartup <<'EOF'
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
xrdb $HOME/.Xresources
startxfce4 &
EOF
chmod +x ~/.vnc/xstartup
# Restart VNC to apply the new session
vncserver -kill :1 || true
vncserver :1
4) Install noVNC and Publish over HTTP
noVNC provides the browser client; websockify proxies WebSocket to the local VNC server.
sudo apt -y install novnc websockify
# Serve the client and proxy to localhost:5901
authbind --deep websockify --web=/usr/share/novnc/ 0.0.0.0:6080 localhost:5901
# ("authbind --deep" is optional; if unavailable, just run websockify as shown below)
# websockify --web=/usr/share/novnc/ 0.0.0.0:6080 localhost:5901
Open http:// and connect (the page usually auto‑fills localhost:5901).
5) Enable HTTPS with a Self‑Signed Certificate (IP‑only)
Encrypts traffic quickly when you do not have a domain. Your browser will warn you about the untrusted certificate.
sudo mkdir -p /etc/ssl/novnc
sudo openssl req -x509 -nodes -newkey rsa:2048 \
-keyout /etc/ssl/novnc/novnc.key \
-out /etc/ssl/novnc/novnc.crt -days 365
# Common Name (CN) = your EC2 public IP
sudo chmod 644 /etc/ssl/novnc/novnc.crt
sudo chmod 600 /etc/ssl/novnc/novnc.key
# Relaunch noVNC with TLS (same port 6080)
sudo websockify --web=/usr/share/novnc/ \
--cert=/etc/ssl/novnc/novnc.crt \
--key=/etc/ssl/novnc/novnc.key \
0.0.0.0:6080 localhost:5901
Visit https:// and click through the certificate warning.
6) HTTPS with Let's Encrypt (Standalone — No Nginx)
This requires a DNS record (A) pointing a hostname to your EC2 IP; Certbot will temporarily bind to port 80 to solve the challenge.
- Create DNS A record:
yourhost.example.com →. - Ensure the Security Group allows TCP 80 from the internet.
- Issue the certificate with Certbot's standalone mode:
sudo apt -y install certbot
sudo systemctl stop novnc || true # free port 80 if needed
sudo certbot certonly --standalone -d yourhost.example.com
# Start noVNC with the issued certs
sudo websockify --web=/usr/share/novnc/ \
--cert=/etc/letsencrypt/live/yourhost.example.com/fullchain.pem \
--key=/etc/letsencrypt/live/yourhost.example.com/privkey.pem \
0.0.0.0:6080 localhost:5901
sudo crontab -e → add 0 3 * * * certbot renew --quiet. Reload noVNC after renew.7) Make noVNC Persistent with systemd
Keep the service running across reboots. Choose one of the HTTPS variants and adjust paths accordingly.
# Example: self‑signed cert paths
sudo tee /etc/systemd/system/novnc.service >/dev/null <<'EOF'
[Unit]
Description=noVNC WebSocket proxy
After=network.target
[Service]
Type=simple
User=kali
ExecStart=/usr/bin/websockify --web=/usr/share/novnc/ \
--cert=/etc/ssl/novnc/novnc.crt --key=/etc/ssl/novnc/novnc.key \
0.0.0.0:6080 localhost:5901
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now novnc
Verification — Quick Checks
# VNC server listening on 5901?
ss -tulnp | grep 5901
# noVNC / websockify listening on 6080?
ss -tulnp | grep 6080
# Logs for certbot / novnc
sudo journalctl -u novnc -e --no-pager
sudo tail -n 200 /var/log/letsencrypt/letsencrypt.log
Troubleshooting (Fast Fixes)
- VNC connection refused / timeout: open SG ports; confirm
vncserver :1is running; verify withss -tulnp | grep 5901. - noVNC can't reach VNC: ensure websockify started with
localhost:5901and not bound tolocalhost:6080only; prefer0.0.0.0:6080. - "Too many authentication failures" in VNC viewer: wait a minute; then reset with
vncpasswdand reconnect. - HTTPS cert warning: expected for self‑signed; for trusted lock, use a domain + Let's Encrypt standalone.
- Certbot NXDOMAIN: DNS A record not propagated or wrong host. Verify with
dig yourhost.example.com +short. - Systemd unit fails (PID/protocol): avoid template complexities; run plain
vncserver :1and manage with simple scripts if needed.
Security Hardening Checklist
- Restrict SG to your IP for 22 and 6080 (and 5901 if exposed).
- Use strong VNC passwords:
vncpasswd. - Prefer HTTPS (even self‑signed) to encrypt browser traffic; for production, use a domain + Let's Encrypt.
- Consider SSH tunneling instead of exposing 5901 publicly.
- Enable basic OS hardening: updates,
ufw, disable root SSH, and optionalfail2ban.
# Example ufw policy
sudo apt -y install ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 6080/tcp
sudo ufw enable
Session Notes & Fixes (Highlights from Our Chat)
Below are the specific issues we hit during the build and the concise fixes you can apply if you run into the same symptoms.
A) Public IP changed after stop/start
- EC2 assigns a new public IP on every stop/start unless you attach an Elastic IP.
- What to redo after an IP change:
- Update your Security Group source IP ranges for ports 22, 6080 (and 5901 if used).
- If you use a domain, update the DNS A record to the new IP and wait for propagation.
- noVNC/VNC do not need to be reinstalled; just start them again if they were not enabled as services:
vncserver -kill :1 || true
vncserver :1
sudo systemctl restart novnc || \
sudo websockify --web=/usr/share/novnc/ 0.0.0.0:6080 localhost:5901
B) Keep noVNC running after closing PuTTY
noVNC started in a terminal stops when that terminal closes. Use one of these:
- systemd (recommended) — see the Make it Persistent section.
- tmux — lightweight and quick:
sudo apt -y install tmux
# start a session and run websockify inside
tmux new -s novnc
websockify --web=/usr/share/novnc/ 0.0.0.0:6080 localhost:5901
# detach with Ctrl-b then d; reattach later: tmux attach -t novnc
C) See previous commands & capture output
# Show command history with timestamps
HISTTIMEFORMAT="%F %T "; export HISTTIMEFORMAT; history | tail -n 200
# Your persistent history file
cat ~/.bash_history | tail -n 200
# Record an entire terminal session into a file
script -a ~/session.log # type 'exit' to stop; view later with less ~/session.log
D) VNC: "Too many authentication failures"
- Wait ~60s (many servers apply a short lockout).
- Reset the VNC password:
vncpasswd. - Restart VNC cleanly:
vncserver -kill :1 || true
vncserver :1
- On the viewer, clear saved credentials & retry.
E) XFCE PolicyKit Agent already exists
This warning appears if multiple authentication agents start. It is harmless and safe to close. To silence it:
# Disable the extra agent (example path may vary by build)
sudo chmod -x /etc/xdg/autostart/polkit-gnome-authentication-agent-1.desktop || true
F) Certbot NXDOMAIN
Let's Encrypt could not find your hostname in DNS. Verify and retry once propagated:
dig +short yourhost.example.com
# If no IP returns, fix the DNS A record first.
G) "Site refused to connect"
- Confirm listeners:
ss -tulnp | grep -E "6080|5901". - Security Group allows the ports from your client IP.
- On HTTPS self‑signed, ensure you started websockify with
--cert/--keyand run withsudoif key permissions are restricted.
H) EC2 status checks 1/2
When only 1/2 checks pass after boot, wait a minute, then consider Reboot. If it persists, stop/start the instance. Ensure the root volume has free space.
I) TightVNC vs Windows Remote Desktop (RDP)
- VNC shares an existing GUI session; protocol is bitmap‑based; no Windows RDP client can connect to VNC directly.
- RDP (via
xrdpon Linux) creates its own session and uses the RDP protocol. You can installxrdpto use Windows Remote Desktop, but it is separate from VNC/noVNC.
J) Ports quick reference
- 22/tcp — SSH
- 5901/tcp — VNC display :1 (usually bound to localhost)
- 6080/tcp — noVNC WebSocket & web client