CentOS7にWindowsからVNCで接続する方法

CentOS7にWindowsからVNC接続する必要が出てきて、いろいろ動かなくてハマったのでメモとして残す。個人的にはVNC接続にこだわらなければ[XRDP](https://qiita.com/SkyLaptor/items/56c9b5f5784f19cac225)使ったほうが手っ取り早いとは思う...

## 検証環境
* CentOSマシン : CentOS7(1708) 64bit (minimal-install)
* Windowsマシン : Windows10(1804) 64bit
* VNCソフト : [UltraVNC](http://www.uvnc.com/) v1.2.2.1

マシンへの基本的なOSインストールは完了しているものとする。

## UltraVNCのインストール(Windows側作業)
WindowsマシンへUltraVNCをインストールする。
インストールウィザードでは少なくとも"UltraVNC Viewer"を選択していること。（他は任意でOK）
![uvnc.png](https://qiita-image-store.s3.amazonaws.com/0/97774/762ca3de-5643-e6aa-2c5c-4dcc66fe3903.png)

## VNCのセットアップ(CentOS側作業)
### GUIコンポーネント(GNOME Desktop)のインストール
CentOSを最小インストールしている場合、GUIに関連するモジュールが不足する。
以下のコマンドにて関連モジュールを一括インストール可能。

```shell-session:
# yum groups install "GNOME Desktop"
```

なお、元から"GNOME Desktop"モードでインストールしている場合は不要。
上記作業後はGUI絡みの設定が別途発生するが、それに関しては[こちら](https://qiita.com/SkyLaptor/items/56c9b5f5784f19cac225)を参照すること。

### TigerVNCのインストール
```shell-session:
# yum install tigervnc-server
```

### パスワード設定
**VNC接続させたいユーザーにログインした状態で**以下のコマンドを実行してパスワードを設定する。今回はrootなのでそのまま実行しているが、別ユーザーであれば`su -`などでそのユーザーに切り替えること。

```shell-session:
# vncpasswd
Password: （任意のパスワード）
Verify: （任意のパスワード再入力）
Would you like to enter a view-only password (y/n)? n　（見るだけのアクセス権が必要であればyとしてパスワードを設定すること）
A view-only password is not used
```

### ファイアウォール(firewalld)にてVNC通信を許可
VNCはTCPの5900+セッション番号を使用する模様。
今回はセッション1しか使わないため、TCP:5901を許可する。

```shell-session:
# firewall-cmd --permanent --add-port=5901/tcp
# firewall-cmd --reload
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: ssh dhcpv6-client
  ports: 5901/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```

ファイアウォールが無効な環境では設定の必要なし。


### VNCの起動確認
セッション番号1番として一時的に起動させ、接続確認を行う。

```shell-session:
# vncserver :1
xauth:  file /root/.Xauthority does not exist

New 'hostname:1 (root)' desktop is hostname:1

Creating default startup script /root/.vnc/xstartup
Creating default config /root/.vnc/config
Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/hostname:1.log

# vncserver -list

TigerVNC server sessions:

X DISPLAY #     PROCESS ID
:1              プロセス番号
```

Windows機にて"UltraVNC Viewer"を起動し、"VNC Server"の欄に`接続先IP/FQDN:VNCポート番号`と入力してから"Connect"を押す。
![test1.png](https://qiita-image-store.s3.amazonaws.com/0/97774/92fc98b2-ff4c-f7c7-a52f-a535e29f3dc7.png)

接続できればパスワードを求められるので、設定しておいたVNCパスワードを入力する。
![test2.png](https://qiita-image-store.s3.amazonaws.com/0/97774/cb47af79-304c-d8a9-f407-37018e28af63.png)

問題なければGUIが表示される。ここまで確認ができたらこの画面はそのまま閉じる。
![test3.png](https://qiita-image-store.s3.amazonaws.com/0/97774/04915621-c45d-83b5-40b0-47e943cfa2ac.png)

問題なく確認が終われば、一時起動させていたプロセスを停止させる。

```shell-session:
# vncserver -kill :1
Killing Xvnc process ID プロセス番号
# vncserver -list

TigerVNC server sessions:

X DISPLAY #     PROCESS ID
```

### VNCの自動起動化
サービスとして登録し、OS起動時に自動的に起動するようにする。

```shell-session:
# cp -p /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service
# vi /etc/systemd/system/vncserver@:1.service
# systemctl daemon-reload
# systemctl start vncserver@:1.service
# systemctl enable vncserver@:1.service
Created symlink from /etc/systemd/system/multi-user.target.wants/vncserver@:1.service to /etc/systemd/system/vncserver@:1.service.
```

```bash:/etc/systemd/system/vncserver@：1.service
※コメント部省略
[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=forking
User=root         ← <USER>をrootに変更
PAMName=login     ← 追記

# Clean any existing files in /tmp/.X11-unix environment
ExecStartPre=-/usr/bin/vncserver -kill %i
ExecStart=/usr/bin/vncserver %i
PIDFile=/root/.vnc/%H%i.pid              ← /home/<USER>を/rootに変更（他のユーザーは<USER>を置き換えるだけで良い）
ExecStop=-/usr/bin/vncserver -kill %i

[Install]
WantedBy=multi-user.target
```

上記作業後、再度Windows機からVNCアクセスを試行して問題なければ作業完了。



## ハマった箇所
### PIDファイルの位置
rootでVNC接続できるようにしようと考えたが、サービスファイル中のユーザー名設定にて何も考えずに`<USER>`を`root`にするとサービスが起動しない。
理由は単純で、そのままユーザー名だけ置き換えると存在しない場所にPIDファイルの場所が指定されてしまう。きちんと存在するパスにすること。

```bash:
【NG】
PIDFile=/home/root/.vnc/%H%i.pid

【OK】
PIDFile=/root/.vnc/%H%i.pid
```

こんなミスをするのはコピペ厨の自分だけだとは思う。/home/rootなんて無いよね...


### ~~メニューバーが表示されない~~
~~VNC接続でき、いざツールを使うぞ！と思ったらWindowsのタスクバーに当たると思われるメニュー類が全く表示されていない。
解決するにはサービス定義ファイルの`[Service]`セクションに`PAMName=login`と書かなければならない模様。
サービス定義を書き換えたら`systemctl daemon-reload`を忘れずに。~~

~~参考: https://qiita.com/HiroshiAkutsu/items/6856e84c6efc126b801c~~
※2018年中旬頃のアップデートでFixされてたはず。

### ログアウトできない
VNC接続後に画面を閉じようとし、普通に画面右上のメニューからログアウトをクリックしても反応しない。これに関しては特に気にせずVNCセッションを切ってしまえば良いかと諦めることにした。