1 前言
场景需求:团队共享桌面、远程办公、研发测试、统一环境管理
上篇覆盖范围:ESXi、域控、vCenter的安装与基础配置
下篇覆盖范围:Horizon的安装与配置
整体目标
- 搭建一套可供团队使用的 VMware 虚拟化桌面环境
- 实现统一认证、集中管理、远程接入与桌面池分发
- 支持后续模板化批量交付和权限管理,以及安全控制(禁止文件拷出)
2 Horizon 8 (2312) 安装与基础配置
2.1 Horizon Client(Connection Server)配置
- 虚拟机规格: 我给了 4CPU、10G内存、90存储
- 系统安装: windows server 2016安装
- 固定 IP 配置: 管理机,设置固定IP
- 步骤:
- 安装虚拟机,加入域中,比如我设定机器名为
horizon.simforge.work(后续也通过这个域名访问) - 传入软件包
VMware-Horizon-Connection-Server-x86_64-xxx.exe,开始安装 - 一路默认下一步就行,中途可能需要设一个密码
- 安装好就可以用
https://<ConnectionServerDomainName>/admin访问了

登录账号密码即域管理员的账号密码,之前在域控服务器里设置过
2.2 事件数据库配置
事件数据库用于记录Horizon事件,不配置也不影响正常使用,只是没有审计日志和错误信息。(但安装起来还挺麻烦的,主要是安装包的获取)
我把数据库配置在了域控机器上。
- SQL Server安装,我选择的是:
cn_sql_server_2016_enterprise_x64_dvd_8699450 - SQL Server Management Studio安装,下载
SSMS-Setup-CHS.exe安装包 - 新建一个数据库,如
horizon_log(可以专门建一个数据库用户,记得开启SQL Server验证方式)
- 在Horizon里链接到数据库即可(使用刚创建的用户)

3 桌面模板与桌面池配置
3.1 制作桌面模板机
- vCenter中创建 Windows/Ubuntu 虚拟机(根据之前下载的镜像)
- 将虚拟机加入域
- 安装 VMware Tools: Windows直接通过vCenter安装,Ubuntu安装
open-vm-tools - 安装 Horizon Agent:
VMware-Horizon-Agent-x86_64-2312-xxxx.exe,还有一个VMware-Horizon-Agent-Direct-Connection-x86_64-2312-xxx.exe不知道具体有啥用,想装就装吧(一路默认安装即可)

- 系统优化与基础配置:
- 网络配置(通过交换机设置好DHCP服务器,这里不用手动配置,自动获得ip即可,记得DNS要指向域控服务器)
- 安装必要的软件、卸载无用的组件

3.2 创建桌面池
- 测试阶段建议选择手动池
- 当模板机配置好了建议选择自动桌面池中的完整虚拟机(即时克隆适合临时使用,不适合团队长期使用)
- 桌面池授权: 我这里直接授权
simforge_user用户组 - 计算机分配: 待虚拟机创建好后手动进行用户分配
- 使用VMware Horizon Client进行连接测试

4 Horizon 自定义&&安全配置
这部分配置图文资料比较少,有些官方文档也感觉和实际对不太上,我试了挺久才弄好的
4.1 导入配置模板
参考官方说明,将
VMware-Horizon-Extras-Bundle-2312-xx.zip导入到域控服务器里(这个文件在Horizon安装包里应该可以找到)解压缩文件,并将 ADMX 文件复制到 Active Directory 服务器。
a. 将.admx文件复制到 Active Directory 服务器上的%systemroot%\PolicyDefinitions文件夹。
b. 将语言资源 (.adml) 文件夹复制到 Active Directory 服务器上的%systemroot%\PolicyDefinitions中。
c. 在 Active Directory 服务器上,打开组策略管理编辑器并在该编辑器中输入模板文件在安装后所在的路径。最好新建一个组策略,不要在默认的策略上改,如图:

- 为远程桌面启用环回处理:
a. 在 Active Directory 服务器上,打开组策略管理控制台。
b. 展开您的域,右键单击为组策略设置创建的 GPO 并选择编辑。
c. 在组策略管理编辑器中,导航到计算机配置 > 策略 > 管理模板: 策略定义 > 系统 > 组策略。
d. 在右侧窗格中,双击配置用户组策略环回处理模式。
e. 选择已启用,然后从模式下拉菜单中选择一个环回处理模式。
f. 我选择的是合并模式:即应用的用户策略设置结合了计算机 GPO 与用户 GPO 中包含的设置。如果发生冲突,则优先选用计算机 GPO。

- 导入完成后应该可以看到各种各样的配置选项了,分计算机设置和用户设置两部分,其中有些重复的(如剪贴板设置在两个里面都有),有些是独有的(如水印设置在用户设置里面有)

4.2 Horizon其他配置(针对Windows客户机)
根据需求在组策略里修改配置即可,注意最好计算机和用户策略都改了,免得有时候不生效。
- 关闭USB、扫描仪重定向(处于安全性需求)
- 设置各种超时时间,免得动不动退出登录了(一部分配置是在Horizon Web端的全局配置里修改的)
- 开启用户水印、定义水印样式
4.2.1 剪贴板重定向、拖放文件
- 允许双向剪贴板共享
- 控制剪贴板大小上限(如20KB)
- 设置文件拖放方向(仅从客户端到代理)
不过好像拖放文件只对windows系统生效,linux只能通过驱动器重定向拷贝文件进去
4.2.2 设置驱动器重定向只读
这个设置找的我好苦啊,官方文档说的根本就是错的(针对2312版本)。最后还是在一篇远古博文中找到了对应的设置方法。
这个需要在虚拟机上修改注册表,因此最好在模板机就调好,并且控制好用户权限,避免用户可以修改该选项
(默认没有permissions这个项,手动加上并设置为r,默认应该是rw)
4.3 Horizon其他配置(针对Ubuntu客户机)
参考官方文档,linux上的配置和Windows有较大区别。
4.3.1 配置文件修改
sudo cp /etc/vmware/config.template /etc/vmware/config
这个需要在虚拟机上修改文件,因此最好在模板机就调好,并且控制好用户权限,避免用户可以修改该文件
(这就是为什么我在上篇中配置sudoer权限时写了一大串)
ubuntu2204% cat /etc/vmware/config
#Enable/Disable the build to lossless mode. Default is FALSE
#RemoteDisplay.buildToPNG=TRUE
#Enable/Disable the left-handed mouse support on Ubuntu/SUSE platform and
#the Mate Desktop of Redhat platform. Default is False.
#For the other Desktop of Redhat and CentOS platform, user can select
#left-handed mouse at system UI.
#mksVNCServer.useUInputButtonMapping=TRUE
#Enable/Disable the audio out. Default is TRUE.
#RemoteDisplay.allowAudio=FALSE
#Set clipboard redirection. Default is 2. 0 means disable; 1 means both directions; 2 means from client to agent only, 3 means from agent to client only.
Clipboard.Direction=1
#Set clipboard maximum size which should be specified in KBytes. Default is 1024 KBytes.
mksvchan.clipboardSize=10
#Enable/Disable the smartcard redirection. Default is TRUE
#VVC.ScRedir.Enable=FALSE
#Set the max of the reader contexts for the smartcard redirection. Default is 16
#VVC.ScRedir.MaxReaderContexts=32
#Loglevel for the smartcard redirection. Log level include [ info | debug]. Default is info.
#VVC.ScRedir.logLevel=debug
#Set the max reader contexts supported by pcscd. Default is determined by pcscd.
#pcscd.maxReaderContext=32
#Set parsing the message body or not. Default is determined by pcscd.
#This option only takes effect if pcscd.maxReaderContext is set.
#pcscd.readBody=TRUE
#Loglevel for pcscd. Log level include [ info | debug]. Default is info.
#pcscd.logLevel=debug
#Enable/Disable audio in feature. Default is TRUE
#VVC.RTAV.Enable=FALSE
#Loglevel for rtav process. Log level include [error | info | debug | trace]. Default is info.
#RTAV.logLevel=debug
# Maximum rate at which frames can be captured from Webcam per second, Minimum = 1 Maximum = 30. No limit is set by default.
#VVC.RTAV.WebcamMaxFrameRate=15
# Maximum width in pixels of an image frame when capturing from Webcam. Available range of values: 32 - 4096, no limit is set by default.
#VVC.RTAV.WebcamMaxResWidth=1920
# Maximum height in pixels of an image frame when capturing from Webcam. Available range of values: 32 - 2160, no limit is set by default.
#VVC.RTAV.WebcamMaxResHeight=1080
# Sets the default image resolution width, this is used if no resolution value is defined by the user.
# Available range of values: 32 - 4096, no value is set by default.
#VVC.RTAV.WebcamDefaultResWidth=320
# Sets the default image resolution height, this is used if no resolution value is defined by the user.
# Available range of values: 32 - 2160, no value is set by default.
#VVC.RTAV.WebcamDefaultResHeight=240
#Loglevel for vmware-CDRServer.log. log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#cdrserver.logLevel=debug
#To prevent the client from sharing additional folders (that is, folders that are not specified with cdrserver.shareFolders). Default is FALSE.
#cdrserver.forcedByAdmin=TRUE
#To specify the folders client can share and the permission for each folder.
#cdrserver.sharedFolders=c:\Users\folder1,R;c:\Users\folder2,R;/home/user,R
#To prevent write access to all folders that are shared with the remote desktop, default value is RW means all shared folders are readable and writable.
cdrserver.permissions=R
#To enable the write cache from agent towards the client side. Default is TRUE.
#cdrserver.cacheEnable=FALSE
#Setup customized shared folder path.
#cdrserver.customizedSharedFolderPath=/mnt/
#Loglevel for vmware-vvcProxy-Node log file. log level include [ fatal | error | warn | info | debug | trace | all ]. Default is info.
#vvc.logLevel=debug
#Loglevel for vmware-vdpService-Server log file. log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#vdpservice.log.logLevel=debug
#To enable/disable VVC heartbeats. The value can be 0|1, means disable|enable VVC heartbeats, Default is enabled.
#vvc.VVCHeartbeats=0
#Specifies the maximum bandwidth, in kilobits per second (kbps), for a VMware Blast session. The bandwidth includes all imaging, audio, virtual channel, USB, and VMware Blast control traffic. The default value is 1 Gbps.
#RemoteDisplay.maxBandwidthKbps=1000000
#Specifies the minimum bandwidth, in kilobits per second (kbps), that is reserved for a VMware Blast session. The default value is 256 kbps.
#RemoteDisplay.minBandwidthKbps=256
#Specifies the maximum rate of screen updates. Use this setting to manage the average bandwidth that users consume. Valid value should be between 3 and 60. The default value is 30 updates per second.
RemoteDisplay.maxFPS=60
#Enable/Disable the Blast protocol statistics in mks log, such bandwidth, FPS, RTT, ... Default is FALSE
RemoteDisplay.enableStats=TRUE
#Enable/Disable H.264 Encoding. Default is TRUE
#RemoteDisplay.allowH264=FALSE
#Max H264 Quantization Parameter (MINIMUM H264 QUALITY for the SW H264 encoder). Default is 36. Accept values from 0 to 51, but the value should be set larger than the value of RemoteDisplay.qpminH264.
#RemoteDisplay.qpmaxH264=36
#Min H264 Quantization Parameter (MAXIMUM H264 QUALITY for the SW H264 encoder). Default is 10. Accept values from 0 to 51, but the value should be set less than the value of RemoteDisplay.qpmaxH264.
#RemoteDisplay.qpminH264=10
#Specifies the image quality for the JPEG/PNG encoded desktop display. The low-quality settings are for areas of the screen that change often, for example, when scrolling occurs.
#The high-quality settings are for areas of the screen that are more static, resulting in a better image quality. You can specify the following settings:
#Available range of values: 1 - 100, default: 25
#RemoteDisplay.minQualityJPEG=25
#Available range of values: 1 - 100, default: 35
#RemoteDisplay.midQualityJPEG=35
#Available range of values: 1 - 100, default: 90
#RemoteDisplay.maxQualityJPEG=90
#Enable/Disable mouse cursor warping support. This enables the remoted desktop/application to change the mouse position without the user moving the mouse. Default is FALSE.
#RemoteDisplay.enableCursorWarping=TRUE
#Enable/Disable UDP protocol support, Default is TRUE
#RemoteDisplay.enableUDP=FALSE
#Enable/Disable Network Continuity, Default is TRUE
#RemoteDisplay.enableNetworkContinuity=FALSE
#Enable/Disable Network Intelligence, Default is TRUE
#RemoteDisplay.enableNetworkIntelligence=FALSE
#Loglevel for vmware-UsbRedirPlugin. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#UsbRedirPlugin.log.logLevel=debug
#Loglevel for vmware-UsbRedirServer. Log level include [ error | warn | info | debug | trace | verbose]. Default is info. If log level is trace, it will dump all the binary data. If the log level of vmware-UsbRedirServer is debug or trace, "UsbRedirServer.log.throttleBytesPerSec" should be set to "-1".
#UsbRedirServer.log.logLevel=debug
#UsbRedirServer.log.throttleBytesPerSec=-1
#Enable the log file for TrueSSO feature. Log level include [error | warn | info | debug | trace | verbose]. The log file is disabled by default.
#VMWPkcs11Plugin.log.enable=true
#VMWPkcs11Plugin.log.logLevel=debug
#PLZ refer to https://www.vmware.com/content/dam/digitalmarketing/vmware/en/pdf/techpaper/vmware-horizon-view-usb-device-redirection-white-paper.pdf for USB Configuration. The format of USB Config such as:
#viewusb.IncludeVidPid=m:vid-xxxx_pid-xxxx
#viewusb.AllowKeyboardMouse=o:true
#Loglevel for collabui. Log level include [ error | info | debug]. Default is info. If log level is debug, it will dump every entrance of collabui functions and the collaborator list's content.
#collaboration.logLevel=debug
#Specifies the maximum collaborators. Use this setting to manage how many users can be added to one session. Valid value should not be greater than 20. The default is 5.
#collaboration.maxCollabors=20
#Enable/Disable the invitation via email, Default is TRUE
#collaboration.enableEmail=FALSE
#Enable/Disable passing input control to other collaborators, Default is TRUE
#collaboration.enableControlPassing=FALSE
#Customized server URL to include in the invitation message for Session Collaboration feature.
#collaboration.serverUrl=""
#Loglevel for BlastServer process. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#BlastServer.log.logLevel=debug
#Loglevel for BlastProxy process. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#BlastProxy.log.logLevel=debug
#BlastProxy.log.throttleBytesPerSec should be set to "-1" if the log level is set to debug or trace, Default value is 1000.
#BlastProxy.log.throttleBytesPerSec=-1
#HTTP server thread pool size, default is 10.
#BlastProxy.NumHttpThreads=10
#Enable/Disable udp forwarding, default is TRUE.
#BlastProxy.UdpEnabled=FALSE
#Enable/Disable dump udp statistics, default is FALSE.
#BlastProxy.enableDumpUdpStatistics=TRUE
#Loglevel for desktopDaemon process. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#DesktopDaemon.log.logLevel=debug
#Loglevel for desktopWorker process. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#DesktopWorker.log.logLevel=debug
#TTY number for Xorg of Linux Agent, it is used in physical machine only. This value should greater than 0. Default is 7.
#DesktopWorker.ttyNum=7
#Loglevel for desktopController process. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#DesktopController.log.logLevel=debug
#Loglevel for rdeSvc process. Log level include [error | warn | info | debug]. Default is info.
#rdeSvc.logLevel=debug
#Loglevel for appScanner process. Log level include [error | warn | info | debug]. Default is info.
#appScanner.logLevel=debug
#Semicolon separated application executable path list that could be blocked from launching and creating unity window.
#rdeSvc.blockedWindows=/usr/libexec/gnome-terminal-server;
#Enable/Disable optimized seamless window resize, default is TRUE.
#rdeSvc.enableOptimizedResize=FALSE
#Enable/Disable display scaling. This option only works if DPI sync feature is enabled.
#Display scaling resizes the screen to auto fit the font size when the DPI is a mismatch between client
#and agent, the default value is FALSE.
#rdeSvc.allowDisplayScaling=TRUE
#Configure app window's executable path and the app's desktopfile name in
#a xml file, the xml file should be configured like the example below.
#<WINDOWEXECPATTERNCONFIG>
# <WINDOWEXECPATTERN>
# <EXECPATTERN>gnome-terminal-server</EXECPATTERN>
# <TARGETPATTERN>org.gnome.Terminal</TARGETPATTERN>
# </WINDOWEXECPATTERN>
#</WINDOWEXECPATTERNCONFIG>
#The EXECPATTERN should be configured with the basename of the commandline to
#launch the app and TARGETPATTERN should be configurd with the app's .desktop
#file name(remove the suffix ".desktop")
#The configured xml file's path should be set in the line below.
#
#rdeSvc.execPatternsConfig=path_to_execpattersiconfig_file
#Enable/Disable printer redirection feature. The default value is TRUE.
printSvc.enable=FALSE
#Customized printer drivers(PPD) on Agent if user don't need NPD or UPD. In this option, the name is the client side printer name, PPD
#path is the absolute ppd file path on Agent. Each item in option must be followed by a semicolon, the entire option must be enclosed
#in quotation marks.
#printSvc.customizedPpd="PinterName1=PPDPath1;PrinterName2=PPDPath2;"
#Update the virtual printer's ppd file to use PDF as the print format. This option only works for Linux/Mac client. Default is TRUE.
#printSvc.usePdfFilter=FALSE
#Set print job owner name as local user name or not. TRUE for local user name, otherwise the session logon user name will be used. Default is FALSE.
#printSvc.jobOwnerAsLocal=TRUE
#Enable/Disable printer watermark feature. Default is FALSE. It needs qpdf to be installed. Please refer to the chapter "Configure VMware Integrated Printing for Linux Desktops" in user guide.
#printSvc.watermarkEnabled=TRUE
#Loglevel for printSvc process. Log level include [error | warn | info | debug]. Default is info.
#printSvc.logLevel="debug"
#Customized papers config file used to filter the papers, papers not listed in the config file will be ignored. The paper information
#in the config file must follow specific rules, otherwise printSvc will fail to parse it. Each line in the config file follows format
#"keyword, name, widthMm, heightMm, widthPts, heightPts". Keyword is a unique string that represents the paper, only allow ASCII
#characters within the range of decimal 33 to decimal 126 inclusive, name is the paper display name on the print UI, widthMm and heightMm
#are the 10 times paper size in mm, widthPts and heightPts are paper size in points. This is a global config that will affect all virtual
#printers. Please note that this option is only valid for Windows client.
#Below is the content of a sample paper list file:
#Letter, Letter, 2159, 2794, 612, 792
#A3, A3, 2970, 4200, 842, 1191
#A4, A4, 2100, 2970, 595, 842
#printSvc.paperListFile=path_to_paper_list_file
#This config item provides the ability to set the default print options when applications don't provide them. All the options are space
#separated, their default value and range are listed as below(case sensitive):
#printSvc.defaultPrintOptions="ColorMode=Color[Mono] Duplex=None[DuplexTumble|DuplexNoTumble] PageSize=9 number-up=1 number-up-layout=None[lrbt|lrbt|rltb|rlbt|tblr|tbrl|btlr|btrl] OutputOrder=Normal[Reverse] page-set=all[even|odd] noCollate[Collate]"
#Printer Filter can be configured to filter the virtual printers not to be added. Printers can be filtered based on the printer name, driver name or driver vendor name. The filter supports logical combination of multiple query conditions using AND, OR, NOT and Bracket. Each query condition in the filter supports Wildcard (asterisk and question mark) and Regular Expression (JavaScript Dialect and substring matching). The value on the right side of = or != should be enclosed with single quotation.
#printSvc.printerFilter="(DriverName='DrName1' OR DriverName='DrName2') AND PrinterName!= 'PrNa.?e'"
#Enable/Disable watermark feature. The default value is FALSE.
#rdeSvc.enableWatermark=TRUE
#Opacity: the transparency level of the text. The range is 0-255. The default value is 50.
#rdeSvc.watermark.opacity=50
#Text Rotation, a specific angle for the watermark text. The default value is 45.
#rdeSvc.watermark.rotation=45
#Image Layout: the watermark layout on the screen, which is divided into nine squares:
#0: Tile, watermark is positioned in all 9 squares. This layout is always used for application sessions.
#1: Center, watermark is positioned in the center square.
#2: Multiple, watermark is positioned in the center and four corner squares. If the watermark size exceeds the box size, it is scaled to maintain the aspect ratio.
#The default value is 0.
#rdeSvc.watermark.fit=0
#The space around the watermark for the Tile layout. If the watermark is scaled, the margin will also be scaled. The default value is 50.
#rdeSvc.watermark.margin=50
#The watermark font size. The default value is 10.
#rdeSvc.watermark.fontSize=10
#The watermark font type. The default value is serif.
#rdeSvc.watermark.font="serif"
#Enable this setting to configure a watermark to appear on your virtual desktop. Enter information you want to display as the watermark in Text.
#Options are:
#$BROKER_USER_NAME
#$BROKER_DOMAIN_NAME
#$USER_NAME
#$USER_DOMAIN
#$MACHINE_NAME
#$REMOTE_CLIENT_IP
#$CLIENT_CONNECT_TIME
#The character limit is 1024 characters and 4096 characters after expansion. The text will be truncated if it exceeds the maximum length.
#rdeSvc.watermark.template="$USER_DOMAIN\$USER_NAME\n$MACHINE_NAME On $CLIENT_CONNECT_TIME\n$REMOTE_CLIENT_IP"
#The minimum number used for X display allocation. Default is 100 and must not be negative.
#Be careful to set the value in [0,9] which is very likely used by Display Manager.
#This item should be little than 59535 to avoid XDMCP port being illegal.
#For VDI mode, the counts from Desktop.displayNumberMin to Desktop.displayNumberMax must not greater than 60.
#For multi-session, the counts from Desktop.displayNumberMin to Desktop.displayNumberMax must be 60.
#Desktop.displayNumberMin=100
#The maximum number used for X display allocation. Default is 159 and must not be negative.
#Be careful to set the value in [0,9] which is very likely used by Display Manager.
#This item should be little than 59535 to avoid XDMCP port being illegal.
#For VDI mode, the counts from Desktop.displayNumberMin to Desktop.displayNumberMax must not greater than 60.
#For multi-session, the counts from Desktop.displayNumberMin to Desktop.displayNumberMax must be 60.
#Desktop.displayNumberMax=159
#Loglevel for greeter. Log level include [warn | error | info | debug]. Default is info.
#Greeter.logLevel=debug
#Loglevel for Session Recording library. Log level include [ error | warn | info | debug | trace | verbose]. Default is info.
#VMBlastRec.log.logLevel=debug4.3.2 设置驱动器重定向只读
修改上述配置文件中的:
#To prevent write access to all folders that are shared with the remote desktop, default value is RW means all shared folders are readable and writable.
cdrserver.permissions=R即可
5 总结
本文分上下两篇,完整记录了一套基于 ESXi、Windows 域控、vCenter 和 Horizon 8(2312) 的团队虚拟桌面环境搭建过程:
- 上篇主要解决底层基础设施问题,包括 ESXi 宿主机安装、管理网络配置、域控与 DNS 部署、客户端加入域,以及 vCenter 的安装和纳管配置;
- 下篇则进一步完成 Horizon Connection Server、事件数据库、桌面模板机、桌面池以及组策略和安全选项的配置。
从实际使用角度看,这套方案已经能够满足团队统一认证、集中管理、远程接入和标准化桌面交付的基本需求。通过 vCenter 统一管理底层虚拟化资源,再配合 Horizon 对桌面模板、桌面池和用户权限进行组织,可以较好地支撑团队研发、测试和日常办公场景。
同时,文章里也补充了不少实际踩坑后的经验,比如 Windows 和 Ubuntu 加入域的方法差异、Linux 桌面模板的 Agent 配置方式、组策略环回处理、驱动器重定向只读、剪贴板与拖放控制、水印显示等内容。