Ubuntu18.04 LTSにVNCでリモートデスクトップ接続する

# はじめに

本記事は、Windows10からUbuntu18.04 LTSに**x11vnc**＋**VNC Viewer**でリモートデスクトップ環境を整えた際の、試行錯誤や実施内容・手順などをまとめたものです。

Windows10を普段は使用しているのですが、開発用サーバとして別途用意したUbuntu18.04 LTSにリモートデスクトップ接続できるようにしました。
普段はssh接続のターミナルやVS CodeのRemote Developmentを利用して開発していますが、その上で**デスクトップ接続**が必要になったことがありました。ヘッドレスでないウェブブラウザを使った開発や確認がしたいとかそんな感じです。

ただ環境によって上手くいく・いかないはあると思いますので、参考程度に捉えていただければと思います。

# TL;DR
結論として、Ubuntu18.04のディスプレイマネージャを**LightDM**にして、**x11vnc**というVNCサーバを入れ、Windowsには**VNC Viewer**というVNCクライアントを入れました。
そしてx11vncをsystemdに登録してサーバマシン起動時に自動起動するように設定しました。

「gdm3じゃないなら用がないよ」という方は回れ右で大丈夫かと。


# 今回の要件など
* 前提条件
    * Ubuntu18.04 LTSにはGPUを積んでおり、NVIDIA driverを入れている
    * Ubuntuには複数のユーザアカウントを作成しており、ADアカウントのユーザもある
    * （追記）UbuntuはディスプレイにHDMIで接続している（画面電源は基本オフ）
* 要件
    * **Ubuntuには複数ユーザアカウントがあるので、ログイン前からデスクトップ接続できるようにし、リモートでユーザ選択・ログインしたい**
    * ADアカウントでのログイン認証がきちんとできないといけない
    * クライアントソフトのウィンドウサイズによって柔軟に描画してほしい（拡大縮小時に縦横比が崩れること等が嫌）
    * クリップボードも共有したい

特に「ログイン前からデスクトップ接続できるようにしたい」は一番大事な要件でした。Ubuntuの不調などでsshからリブートを掛けたりしますし、付けっぱなしのログインしっぱなしということは考えられないからです。


# やったこと
以下、試行錯誤の道中も含めてまとめます。道中はいらないよ！という方は[x11vncの項目](#x11vncにした)だけ読めば大丈夫です。

## VNCサーバ

Ubuntu側に入れるVNCサーバの検討と導入についてです。
またVNCサーバの動作チェックにVNCクライアントも必要なので、ひとまず何かしらWindows側にも入れておきましょう。

### その前にまずxrdpは？

そもそもリモートデスクトップ接続をする手段としてはVNC以外にRDPというプロトコルもありまして、そちらも試していました。RDPならWindows標準搭載のリモートデスクトップ接続から表示できますしね。
ただし、ADアカウントで何故かログインできなかったり、青緑の画面で止まったりと上手くできなかったので、却下となりました。何か設定ファイルが壊れていたとかあるのでしょうか。知見者がいれば解決策を伺いたいです！

### Ubuntu18.04 LTS標準搭載の「画面共有」機能は？

* 参考：[Ubuntu18.04でモニタレスVNC](http://rarak.jp/16022)

標準搭載のVNCサーバ機能ということで、こちらも試してみました。裏側ではVinoを使っているようですね。
試してみた結果、ログイン中のユーザにはVNCクライアントから接続できたのですが、どうやら**本体にログインしている状態でしか使えず、ログアウトしてしまうとリモートからログイン出来ない様子**…。ログイン後にVNCサーバが自動起動するということですね。

上記を知り合いに相談すると、

> 「Vinoは昔使ったときに微妙だった記憶が…。x11vncが昔から重宝されている印象。それをログイン前のPC起動時から自動起動するように設定すればいいのでは。」

というアドバイスをもらったので、ホイホイそれに乗ってx11vncで行こうという気持ちになりました（ちなみにその人はUbuntu16.04ユーザだったようですが）。
Vinoをログイン前から自動起動する設定にする方法があればこれも行けると思うのですが、調査を諦めてしまいました。Vinoファンの方すみません。

### x11vncにした

そんなこんなでx11vncにしようと思い調べて回り、設定したところ、なんとか要件を満たすことができました。
以下のサイトがかなり参考になりました。

* [Ubuntu 20.04 LTSでのx11vnc設定手順](https://mixture.dcmnjp.net/linux/ubuntu/x11vnc.html) （閲覧時は18.04でしたが）
* [【Ubuntu】起動時にVNCサーバが走るように設定する。](https://freefielder.jp/blog/2015/10/ubuntu-vnc-server-on-startup.html)

参考サイトと被るところも多いですが、以下手順です。

#### ディスプレイマネージャの変更

ディスプレイマネージャとは、簡単に言うとLinuxがログイン画面をGUIで提供するための機能です。
Ubuntu16.04まではLightDM（Unity）が標準だったのですが、18.04からはgdm3（GNOME）に変更になったようですね。
とは言いつつ、好きなディスプレイマネージャに切り替えることが可能です。

x11vncはUbuntu18.04標準ディスプレイマネージャのgdm3では動作しない（？）そうなので、LightDMを導入します。

```terminal
sudo apt-get install lightdm
sudo dpkg-reconfigure lightdm
sudo reboot
```

ディスプレイマネージャを切り替えると、おそらくログイン画面やデスクトップ画面のUIが変わったりするかと思います。
複数個目のデスクトップマネージャを入れた場合、ログイン画面でユーザ名の横辺りに歯車アイコンが出現するので、そこで何のデスクトップマネージャを使うか選びましょう。LightDMを入れたなら「Unity」を選んでください。一回選択したら次回以降はそれがデフォルトになってくれます。


#### VNCサーバのインストール

x11vncをインストールします。

```terminal
sudo apt install x11vnc
```

#### パスワードファイルの作成

VNC接続の際のパスワードファイルを作成します。アカウントのパスワード等とは別物なので好きなパスワードを設定しましょう。ファイル名もなんでもOKです。
今回はどのユーザからもアクセス可能にするため、パスワードファイルを```/etc``` に作ります。（ ```~/``` 以下に作ると複数ユーザからアクセスできない可能性が高いです。）

```terminal
sudo x11vnc -storepasswd /etc/x11vnc.passwd
```

以下のように表示されていくので進めます。

```terminal
Enter VNC password:  ← パスワード入力
Verify password:     ← パスワード確認入力
Write password to /etc/x11vnc.passwd?  [y]/n   ← y か Enter
Password written to: /etc/x11vnc.passwd
```

最後にユーザの読み取り権限を与えます。

```terminal
sudo chmod 644 /etc/x11vnc.passwd
```


#### 動作テスト

一度、手動で起動テストを実行してみます。`-rfbauth`オプションでは前述の作成したパスワードファイルを指定してください。ちなみに `-xkb` がクリップボードを共有させるオプションです。入れないと勿体ない！

```terminal
sudo x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.passwd -rfbport 5900 -forever -loop -xkb -noxdamage -repeat -shared
```

VNCクライアントからIPアドレスで接続してみましょう。クライアントソフトからパスワードを求められますので、先ほど`Enter VNC password:`で設定したパスワードを入力します。画面が表示されれば、x11vncは正常に使えています！

#### 自動起動設定

サーバPC起動時にsystemdで自動起動するよう、ユニットファイル `x11vnc.service` を作成します。

```terminal
sudo vi /etc/systemd/system/x11vnc.service
```

```systemd:/etc/systemd/system/x11vnc.service
[Unit]
Description=x11vnc (Remote access)
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.passwd -rfbport 5900 -forever -loop -xkb -noxdamage -repeat -shared
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
KillMode=control-group
Restart=on-failure

[Install]
WantedBy=graphical.target
```

systemdに登録し、起動させます！

```terminal
sudo systemctl daemon-reload
sudo systemctl enable x11vnc
sudo systemctl start x11vnc
```

これでPCをいくらリブートさせても、ログイン画面からVNCで接続できるようになっているはずです！やったー！確認しましょう(^o^)
私は、ADアカウントでも問題なくログインできること等も確認しました。

#### 注意点

ログイン画面でパスワードの入力後、Enterキー打鍵で入ろうとするとなぜかたまにセッションが壊れ、以下のような現象が起きます…(-_-;)
マウスポインタでクリックしてログインするようにしてください。

* VNCセッションが切れた場合
    * 再度VNCクライアントから接続し直せば、ログイン後のデスクトップが表示されるはず。
* Enterキーがずっと打鍵され続けている現象になった場合
    * デスクトップから端末を開いてCtrl+Cとか押せば止まります。この現象、何をしようとしてもEnterで即決されてしまい、まともに操作できなくなって地味につらいです。
* 他の現象の場合
    * 遭遇していないので分かりませんが何か他にもある気がします。最悪の場合はsshでログインしてリブートしましょう…（リブートしてもx11vnc自動起動により再接続できるという大きな心理的安全性ゆえの暴挙）。

またUbuntu18.04以降とx11vncの相性がちょっと良くないのか、Ubuntu16.04とx11vncの組み合わせのときよりも動作が遅いらしいです。確かに遅延が結構あり、ストレスフルな面もあります。基本的な開発はやはりssh接続のものが良いでしょう。

## VNCクライアント

Windows側に入れるVNCクライアントは正直何でもいいので好きなものを入れてください。
一応いろいろ試してみたので感想をまとめておきます。

* UltraVNC
    * 定番ソフトです。レスポンスや描画品質も悪くないかと。
    * インストール時にサーバとクライアントどっちもインストールできそう（チェックボックスで選択可能）でビビりました。使うならバイナリ版が楽かもしれないですね。
    * ウィンドウサイズを変えるとそれに合わせて画面が縦横比を保たずに伸縮してしまいました。縦横比固定モードにすると拡大縮小できず、諦めました。
* TigerVNC
    * 大きすぎる画面サイズでしか表示されなくて悲しかった記憶。クライアントのウィンドウに画面が収まりきらずスクロールバーが出ており、操作に厳しいものがありました。
* VNC Viewer（VNC Connect）
    * ウィンドウサイズを変えても接続先画面の表示領域は縦横比が保たれながら拡大縮小し、要件にベストマッチでした。よかった～。

<img width="70%" alt="VNCViewer_example.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643580/0872ecbc-0239-07d0-2f5b-9af9b7e751cf.png">


むしろVNC Viewer以外でも縦横比を保ちながら拡大縮小してくれるクライアントって本当に無いんでしょうか？私が設定方法を見落としているだけな気もしますが、ググってもなかなか分からなかったのです。知っている方がいましたら教えてください(^^;)