TigerVNC gives each configured Linux user an independent virtual desktop. That is separate from mirroring whoever happens to be logged in at the physical console.
This walkthrough covers the modern workflow on RHEL 8.3 and later, RHEL 9, Rocky Linux 8/9, AlmaLinux 8/9, and CentOS Stream 9. You map users in /etc/tigervnc/vncserver.users and start the packaged vncserver@:<display>.service unit—no hand-copied systemd files.
Validation environment: Rocky Linux 9.8 (Blue Onyx) with
tigervnc-server-1.15.0-7.el9_8.2. Package installation, thevncserver@:2.serviceunit, configuration parsing, and socket binding were validated in a systemd-enabled test container. GNOME desktop rendering, remote viewer authentication, host firewalld behavior, native-host SELinux labels, and NVIDIA integration require validation on a VM or physical server.
rpm -q tigervnc-servertigervnc-server-1.15.0-7.el9_8.2.x86_64Steps follow Red Hat Enterprise Linux 9 — Remotely accessing the desktop as multiple users. Rocky Linux 10.2 no longer ships tigervnc-server; on RHEL 10 use GNOME Remote Desktop with RDP instead.
Quick reference
| Task | Command or file |
|---|---|
| Map user to display | /etc/tigervnc/vncserver.users → :2=vncuser |
| System-wide session defaults | /etc/tigervnc/vncserver-config-defaults |
| Set VNC password | vncpasswd as the mapped user |
Start display :2 |
sudo systemctl enable --now vncserver@:2.service |
| Identify active firewall zone | sudo firewall-cmd --get-active-zones |
| Set the zone for later commands | ZONE=public — replace public with the active interface zone |
| Open one VNC port (direct access) | sudo firewall-cmd --zone="$ZONE" --permanent --add-port=5902/tcp |
| Connect from client | vncviewer --shared server-ip:2 |
| Check service logs | sudo journalctl -u vncserver@:2.service |
| Restore SELinux labels | Run restorecon as the mapped VNC user on the VNC directories that exist |
TigerVNC Support Across RHEL Versions
| Platform | TigerVNC status | Configuration method |
|---|---|---|
| CentOS Linux 7 | End of life | Legacy custom [email protected] units |
| RHEL 7 | End of normal maintenance; ELS available for RHEL 7.9 | Legacy custom [email protected] units |
| RHEL 8.0–8.2 | Older workflow | Legacy user-specific systemd configuration |
| RHEL 8.3 and later | Available | vncserver.users and packaged systemd template |
| RHEL 9 | Available but deprecated | Same modern workflow |
| Rocky/AlmaLinux 8 and 9 | Available in current repositories | User mapping and packaged systemd unit |
| CentOS Stream 9 | Available | User mapping and packaged systemd unit |
| RHEL 10 / Rocky 10 / AlmaLinux 10 | TigerVNC removed | GNOME Remote Desktop with RDP |
This tutorial follows the RHEL 8.3+ and RHEL 9 method documented in Red Hat's multi-user VNC procedure for RHEL 9 and RHEL 8 remote desktop access. Supported Rocky Linux and AlmaLinux 8 installations are based on the later RHEL 8 lifecycle, so RHEL 8.0–8.2 differences are noted here only. A short RHEL 7 legacy note appears at the end for old installations only.
How TigerVNC Displays and Ports Work
| Display | TCP port | Typical use |
|---|---|---|
:0 |
5900 | Existing local graphical display |
:1 |
5901 | Available, but not the recommended first mapped user |
:2 |
5902 | Recommended first TigerVNC user |
:3 |
5903 | Second TigerVNC user |
The formula is:
TCP port = 5900 + display numberDisplay :2 maps to TCP port 5902. Give each VNC user a unique display number. Several viewers can attach to the same display, but they all see one desktop. To keep more than one viewer connected at once, set alwaysshared on the server or pass --shared from the client; otherwise a new non-shared connection may drop the existing viewers. A TigerVNC session is independent of the physical console.
Do not configure root as a VNC desktop user. This walkthrough uses one regular account named vncuser.
Install TigerVNC and the Desktop Environment
Identify the operating system before you install packages:
grep -E '^(NAME|VERSION)=' /etc/os-releaseNAME="Rocky Linux"
VERSION="9.8 (Blue Onyx)"Confirm that the host is one of the supported RHEL 8.3+/9-family releases listed above before continuing.
Install the TigerVNC server package:
sudo dnf install tigervnc-serverInstall the viewer only when this server will also act as a VNC client:
sudo dnf install tigervncA headless or minimal server still needs a graphical desktop environment before TigerVNC can start GNOME. See what environment groups are available:
dnf grouplist -v --availableOn many RHEL-family servers you install a workstation or server-with-GUI environment, for example:
sudo dnf groupinstall "Server with GUI"Check the desktop sessions available to TigerVNC:
ls -1 /usr/share/xsessions/Example on Rocky Linux 9.8 with GNOME installed:
gnome-custom-session.desktop
gnome-xorg.desktop
gnome.desktopUse the filename without .desktop as the session value. For example, gnome.desktop corresponds to:
session=gnomeA TigerVNC virtual session can run on a headless server once the chosen desktop session packages are installed; you do not need an active local console login for every mapped user.
Verify the packaged files and systemd template:
rpm -ql tigervnc-server | grep -E 'vncserver|tigervnc'systemctl cat [email protected]On RHEL 8 and 9, leave the packaged unit in /usr/lib/systemd/system/. Map users in /etc/tigervnc/vncserver.users instead of copying and editing the unit under /etc/systemd/system/.
Create and Map the VNC User
Create a regular Linux account for the VNC session. Do not use root:
sudo useradd -m vncusersudo passwd vncuserMap the account to display :2 in /etc/tigervnc/vncserver.users:
:2=vncuserFor multiple users:
:2=vncuser
:3=developerThe display number sets both the systemd instance name (vncserver@:2.service) and the TCP port. A user who is already logged into the local graphical session cannot also export the same kind of VNC session.
Configure the TigerVNC Session
Edit system-wide defaults in /etc/tigervnc/vncserver-config-defaults:
session=gnome
alwaysshared
geometry=1920x1080session=gnomepicks the desktop from/usr/share/xsessions/alwayssharedlets multiple viewers stay on the same displaygeometrysets the virtual desktop size
TigerVNC currently permits TLSVnc and VncAuth by default. Declaring the same list explicitly documents the policy but does not harden it:
securitytypes=tlsvnc,vncauthTLSVnc encrypts the VNC connection and then uses VNC password authentication. It does not provide the same certificate-based server identity verification as the X509Vnc security type.
Because VncAuth is still available without TLS transport protection, use direct access only on a trusted network. For untrusted networks, prefer the SSH-only configuration below.
Starting with TigerVNC 1.14, upstream TigerVNC uses the XDG-based per-user configuration file:
~/.config/tigervnc/configOlder RHEL-family packages use:
~/.vnc/configSome RHEL documentation still shows the older path in its configuration priority list. Check the installed package's vncsession manual and the directories your user actually has before editing per-user settings:
man vncsessionsudo -iu vncuser sh -c 'find "$HOME/.config/tigervnc" "$HOME/.vnc" -maxdepth 1 -type f 2>/dev/null'TigerVNC reads configuration files in this order:
/etc/tigervnc/vncserver-config-defaults~/.config/tigervnc/config(or legacy~/.vnc/config)/etc/tigervnc/vncserver-config-mandatory
The mandatory file is loaded last, so it wins when the same option appears in more than one place.
TigerVNC 1.14 and later normally store:
~/.config/tigervnc/config
~/.config/tigervnc/passwd
~/.local/state/tigervnc/Confirm paths on your host with rpm -ql tigervnc-server, man vncsession, and journalctl -u vncserver@:2.service.
Do not rely on hand-edited ~/.vnc/xstartup GNOME or KDE blocks as the main configuration method on RHEL 8/9.
If the display instance is already running, restart it after changing system-wide or per-user options:
sudo systemctl restart vncserver@:2.serviceDuring initial setup, continue to the service startup section below.
The password file can be updated while Xvnc is running because TigerVNC reads it for each incoming connection. Other server settings need a service restart to take effect once the unit is running.
If the server uses the proprietary NVIDIA driver, TigerVNC may require an Xorg-based GNOME session. In /etc/gdm/custom.conf, uncomment:
WaylandEnable=FalseThen add this under [daemon]:
DefaultSession=gnome-xorg.desktopReboot the server after changing the display-manager configuration.
Set the VNC Password and Restore SELinux Contexts
Switch to the mapped user and set a VNC password:
[root@server ~]# sudo -iu vncuser
[vncuser@server ~]$ vncpasswd
The VNC password is separate from the Linux account password. TigerVNC stores an obfuscated value in a user-readable-only file, but this is not secure encryption. Use a unique password and protect the transport with TLS, a trusted network, VPN, or an SSH tunnel.
On TigerVNC 1.14 and later, verify the password file:
ls -lZ ~/.config/tigervnc/passwdConfirm that:
- The file belongs to the mapped VNC user
- Its mode is
600 - It has the default SELinux context for its location
If the context is unexpected, restore it before changing or disabling SELinux:
restorecon -v ~/.config/tigervnc/passwdIf you are migrating an older configuration, restore labels on the directories that exist:
restorecon -RFv ~/.vncrestorecon -RFv ~/.config/tigervncrestorecon -RFv ~/.local/state/tigervncReturn to the administrative shell:
exitThe current TigerVNC layout places the password under ~/.config/tigervnc/passwd and state such as logs under ~/.local/state/tigervnc/.
For traditional TigerVNC password authentication, the password must contain at least six characters, but only the first eight characters are significant. Do not assume that adding characters after the eighth strengthens VncAuth.
Use a unique VNC password and protect the connection with TLS, a VPN, or the SSH-only method described below.
Configure firewalld and Secure Network Access
Pick one access model and stick with it. An SSH tunnel encrypts traffic through the tunnel, but it does not stop direct VNC connections while Xvnc listens on all interfaces and firewalld still permits VNC ports.
Identify the zone attached to the network interface VNC clients use:
sudo firewall-cmd --get-active-zonesSet the applicable zone name. Replace public when your interface uses another zone:
ZONE=publicOption A: Direct connection on a trusted network
For direct access to display :2, add TCP port 5902 to that zone:
sudo firewall-cmd --zone="$ZONE" --permanent --add-port=5902/tcpsudo firewall-cmd --reloadOpening only 5902/tcp is tighter than enabling the predefined 5900–5903 range when you have a single VNC user.
Verify the same zone:
sudo firewall-cmd --zone="$ZONE" --list-ports5902/tcpFor multiple mapped users on displays :2 through :3, enable the predefined service in that zone:
sudo firewall-cmd --zone="$ZONE" --permanent --add-service=vnc-serversudo firewall-cmd --reloadsudo firewall-cmd --zone="$ZONE" --list-servicesvnc-serverTo see which ports that service represents:
sudo firewall-cmd --info-service=vnc-servervnc-server
ports: 5900-5903/tcp--info-service describes the service definition; --zone="$ZONE" --list-services and --zone="$ZONE" --list-ports show what is actually enabled on the interface zone. For displays above :3, open the calculated port in the same zone—for example, display :5 needs TCP port 5905:
sudo firewall-cmd --zone="$ZONE" --permanent --add-port=5905/tcpsudo firewall-cmd --reloadRestrict sources to a trusted administration network when you can instead of exposing VNC to the internet.
Option B: SSH tunnel without exposing VNC
To enforce local-only listening for VNC sessions started through the packaged vncserver@ service, add this option to /etc/tigervnc/vncserver-config-mandatory:
localhostThe mandatory file overrides per-user TigerVNC configuration, so users cannot re-enable external listening through ~/.config/tigervnc/config.
This file is an administrative policy for the packaged vncsession workflow, not a complete security boundary against users who can run Xvnc directly. Keep unnecessary VNC ports closed in firewalld and limit shell access appropriately.
If vncserver@:2.service is already running, restart it after adding localhost:
sudo systemctl restart vncserver@:2.serviceDuring initial setup, enable and start the service in the next section after you finish firewall and mandatory-file changes.
Do not open TCP port 5902 in firewalld for this method. Remove whichever firewalld rule you added earlier in the same zone.
If you opened only TCP port 5902:
sudo firewall-cmd --zone="$ZONE" --permanent --remove-port=5902/tcpIf you enabled the predefined VNC service:
sudo firewall-cmd --zone="$ZONE" --permanent --remove-service=vnc-serverReload and verify the same zone:
sudo firewall-cmd --reloadsudo firewall-cmd --zone="$ZONE" --list-portssudo firewall-cmd --zone="$ZONE" --list-servicesNeither 5902/tcp nor vnc-server should appear when you chose SSH-only access.
Confirm Xvnc listens only on loopback:
sudo ss -lntp | grep ':5902'LISTEN 0 5 127.0.0.1:5902 0.0.0.0:* users:(("Xvnc",pid=1873,fd=9))
LISTEN 0 5 [::1]:5902 [::]:* users:(("Xvnc",pid=1873,fd=10))Create the tunnel from your client. SSH authentication is separate from VNC authentication—the SSH account can be a dedicated administrator or bastion user; vncuser does not need interactive SSH access:
ssh -N -L 5902:127.0.0.1:5902 admin@server-ipAny authorized SSH account for which TCP forwarding is permitted can establish the tunnel. If SSH reports that forwarding is prohibited, check AllowTcpForwarding, PermitOpen, and applicable Match blocks in the SSH server configuration.
Connect through the tunnel:
vncviewer --shared localhost:2If TCP port 5902 is already in use on the client, pick another local port while keeping the remote side on 5902:
ssh -N -L 15902:127.0.0.1:5902 admin@server-ipvncviewer --shared localhost::15902This is the safer choice across an untrusted network. For a longer SSH tunneling walkthrough, see SSH port forwarding. For broader firewall workflows, see the firewalld cheat sheet.
Start, Enable, and Connect to TigerVNC
Enable and start display :2:
sudo systemctl enable --now vncserver@:2.serviceCheck that the unit is active:
systemctl is-active vncserver@:2.serviceactiveSee which address Xvnc is listening on:
sudo ss -lntp | grep ':5902'With direct network access (no localhost in the mandatory file), Xvnc listens on all interfaces:
LISTEN 0 5 0.0.0.0:5902 0.0.0.0:* users:(("Xvnc",pid=1364,fd=9))
LISTEN 0 5 [::]:5902 [::]:* users:(("Xvnc",pid=1364,fd=10))With localhost in vncserver-config-mandatory, the listener is bound to loopback only—see the SSH-only section above for that sample.
The listener output above was collected from a Rocky Linux 9.8 systemd-enabled test container after starting vncserver@:2.service. That confirms package install, unit startup, and socket binding. It does not prove GNOME desktop startup, remote viewer login, session persistence, or host firewalld behavior—validate those on a VM or physical server before you rely on this in production.
Review the unit status and journal when something fails to start:
sudo systemctl status vncserver@:2.servicesudo journalctl -u vncserver@:2.serviceFrom a machine that can reach the server (or through an SSH tunnel), connect with a TigerVNC client:
vncviewer --shared server-ip:2--shared tells the server to keep existing viewer connections. With alwaysshared already set, other viewers may still connect, but passing --shared makes the client intent explicit.
Confirm on your setup that:
- The expected user's GNOME desktop appears
- The session survives closing and reopening the viewer
- Multiple viewers stay connected when
alwayssharedis enabled - You are using the correct display number and port
| Action | Command |
|---|---|
| Start | sudo systemctl start vncserver@:2.service |
| Stop | sudo systemctl stop vncserver@:2.service |
| Restart | sudo systemctl restart vncserver@:2.service |
| Disable at boot | sudo systemctl disable vncserver@:2.service |
| Status | sudo systemctl status vncserver@:2.service |
Configure Multiple Users or Per-User Options
Add another mapping:
:3=developerThen run vncpasswd as developer, start vncserver@:3.service, open TCP port 5903 if you use direct access, and connect to display :3.
The per-user ~/.config/tigervnc/config file (or legacy ~/.vnc/config) can override settings in vncserver-config-defaults when different users need different resolution, desktop name, sharing behavior, or session type. Restart each affected display after you change per-user options.
Troubleshoot TigerVNC Server Problems
| Symptom | Likely cause | Check or recovery |
|---|---|---|
Unit vncserver@:2.service failed |
Invalid user mapping or session configuration | Check vncserver.users and the journal |
| Black or blank screen | Invalid desktop session or missing GNOME packages | Verify installed session and session= value |
| Connection refused | Service not listening or firewall blocking port | Check systemctl, sudo ss, and firewall-cmd --zone="$ZONE" --list-ports |
| Wrong user desktop opens | Incorrect display-to-user mapping | Check /etc/tigervnc/vncserver.users |
| Password rejected | Password was set as another user | Run vncpasswd as the mapped user |
| Permission denied | Wrong ownership or SELinux labels | Check home-directory ownership and run restorecon |
| Display already in use | Existing X or stale VNC session | Check processes, sockets, and service status |
| Service works manually but not through systemd | Old custom unit overrides packaged service | Remove obsolete unit overrides and run daemon-reload |
| GNOME session exits immediately | Missing desktop components or session mismatch | Review journal and available session files |
| GNOME fails with proprietary NVIDIA driver | Wayland is enabled | Disable Wayland, select gnome-xorg.desktop, and reboot |
Cannot connect above display :3 |
vnc-server firewalld service does not cover the higher port |
Open the calculated TCP port manually |
| SSH tunnel reports administratively prohibited | SSH TCP forwarding is disabled | Check AllowTcpForwarding, PermitOpen, and account-specific Match rules |
Useful diagnostics:
sudo systemctl status vncserver@:2.servicesudo journalctl -xeu vncserver@:2.servicesudo ss -lntpsudo firewall-cmd --zone="$ZONE" --list-allloginctl list-sessionsrpm -V tigervnc-serversystemctl status shows whether the unit is active. journalctl surfaces session startup errors. sudo ss -lntp confirms the listener on port 5902. firewall-cmd --zone="$ZONE" --list-all shows whether vnc-server or a custom port is open on the zone attached to your VNC interface.
Migrating from the RHEL 7 TigerVNC Configuration
RHEL 7 used copied unit files such as:
/etc/systemd/system/[email protected]
/etc/systemd/system/vncserver@:1.service
/etc/systemd/system/vncserver@:2.serviceOn RHEL 8.3+ and RHEL 9:
- Record existing users, displays, geometry, and passwords
- Stop and disable old instances—for example
sudo systemctl disable --now vncserver@:2.service—and repeat for each configured display number - Back up and remove only obsolete TigerVNC unit files such as
[email protected]and copiedvncserver@:<display>.serviceinstances under/etc/systemd/system/. Do not remove unrelated systemd service files - Run
sudo systemctl daemon-reload - Map users in
/etc/tigervnc/vncserver.users - Move common settings to
vncserver-config-defaults - Run
restoreconas each mapped VNC user on the TigerVNC directories that exist - Start the packaged
vncserver@:<display>.serviceunit - Test one user before migrating additional accounts
Do not reuse RHEL 7 vncserver_wrapper, runuser, or custom PIDFile examples in the main RHEL 8/9 workflow. On RHEL 7, a Resource limit exceeded failure often involves stale files under /tmp or /tmp/.X11-unix/—see vncserver resource limit exceeded.
Summary
On RHEL 8.3+, RHEL 9, Rocky Linux 8/9, AlmaLinux 8/9, and CentOS Stream 9:
- Install
tigervnc-serverand a GNOME desktop environment - Create a regular account such as
vncuser—notroot - Map the user to display
:2invncserver.users - Set
session=gnomeinvncserver-config-defaults - Run
vncpasswdas the mapped user - Open TCP port
5902in the correct firewalld zone for direct access, or setlocalhostinvncserver-config-mandatoryand use an SSH tunnel - Enable
vncserver@:2.service - Connect with
vncviewer --shared server-ip:2and confirm the desktop loads on your network
On RHEL 10 and compatible 10.x distributions, use GNOME Remote Desktop with RDP instead of TigerVNC. For SSH-protected access, see SSH port forwarding. For firewall management beyond VNC, see the firewalld cheat sheet.
References
- Red Hat Enterprise Linux 9 — Remotely accessing the desktop as multiple users
- Red Hat Enterprise Linux 9 — Deprecated functionalities
- Red Hat Enterprise Linux 8 — Accessing the desktop remotely
- TigerVNC — vncsession
- TigerVNC — vncpasswd
- TigerVNC — vncviewer
- TigerVNC — Xvnc
- Red Hat Enterprise Linux 10 — Removed features (TigerVNC removal)

