UbuntuにVNCサーバーを構築してMacからリモート接続するための備忘録

[過去記事](https://qiita.com/y-vectorfield/items/c5fd815a9cabe5c2d6d8)にて、MacからUbuntu18.04にリモート接続を実現する為の設定方法を投稿しました。しかし、この方法では、Ubuntu18.04側でログインをしている状態でなければ、Ubuntuサーバーにリモートで接続出来ません。なぜならば、Vinoを用いるこの方法では画面共有をしているだけだからです。これでは接続時に毎回Ubuntu側でログインをしておかなければならず、大変不便です。本記事ではTightVNCを用いてVNCサーバーをUbuntu上に構築し、本来のRemote Desktop環境実現を目指します。

:warning: この記事の方法はUbuntu20.04でも有効です．

* 参考

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-20-04-ja

# 環境情報
今回は、以下の環境に[参考記事](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-20-04-ja)を参考にして構築します。Ubuntu 20.04を対象にした構築方法を紹介している記事ですが、Ubuntu 18.04でも問題無く構築出来ました。

* macOS Big Sur 11.04
* Ubuntu 18.04.5 LTS

# 構築方法
参考記事の構築方法を参考に構築を進めます。筆者の環境では過去の構築でVinoがインストールされていたので、競合を避けるため、アンインストールを実施してからセットアップを開始しました。

```bash:Vinoのアンインストール(インストール済の場合)
sudo apt remove -y vino
```

## Xfceデスクトップ環境パッケージのインストール
リモート接続で使用するデスクトップ環境をインストールします。

```bash
sudo apt install -y xfce4 xfce4-goodies
```

:warning: インストール途中にディスプレイマネージャーの選択が求められます．筆者は特にこだわりが無いため，`gdm3`(最初から選択されている)を選択しました．

## VNCサーバーをインストール
VNC(Virtual Network Computing)サーバーをUbuntuサーバーにインストールします。

```bash
sudo apt install -y tightvncserver
```

## VNCアクセスパスワードの設定
アクセスパスワードを設定します。以下のコマンドを実行します。

```bash
vncserver
```

パスワードの設定が求められます。6〜8文字のパスワードを設定します。8文字以上設定した場合は切り捨てられる仕様になっています。このままでは脆弱なパスワードですが、接続のセキュリティを担保するために、この後の行程でSSHトンネルを確立した上で接続を行います。

```bash:実行結果
$ vncserver

You will require a password to access your desktops.

Password: 
Verify:   
Would you like to enter a view-only password (y/n)? n

New 'X' desktop is your_hostname:1

Creating default startup script /home/user/.vnc/xstartup
Starting applications specified in /home/user/.vnc/xstartup
Log file is /home/user/.vnc/your_hostname:1.log

```

## VNCサーバーインスタンスの停止
起動時に使用する実行ファイル(兼構成ファイル)を編集するため、一旦サーバーインスタンスを停止します。

```bash
vncserver -kill :1
```

<details><summary>実行結果</summary><div>

```bash
$ vncserver -kill :1
Killing Xtightvnc process ID 5293
```

</div></details>

## 実行ファイルのバックアップ
実行ファイルを編集する前に、オリジナルのバックアップを作成します。

```bash
cp ~/.vnc/xstartup ~/.vnc/xstartup.bak
```

## 実行ファイルの編集
実行ファイル(`xstartup`)を開きます。

```bash
vim ~/.vnc/xstartup
```

以下の様に編集します。

```bash
#!/usr/bin/env bash                                                                                                                                          

xrdb $HOME/.Xresources
startxfce4 &
```

編集後，実行ファイルとするために実行権限を付与します．

```bash
chmod +x ~/.vnc/xstartup
```

## VNCサーバーの再起動
実行ファイルの編集が完了したら、再起動します。以下のコマンドを実行します。ここで`-localhost`オプションを使用して、ループバックインターフェイスにバインドしています。これで、インストールされているサーバーから発信された接続のみを許可します。これは接続のセキュリティを担保するため、この後設定するSSHトンネルを用いた接続を前提としているためです。

```bash
vncserver -localhost
```

以下の実行結果の`your_hostname:1`の`:1`は次のSSHトンネル確立時に重要な情報となります。実行環境によっては、`:2`や`:3`が表示される場合も有ります。(特にVNCサーバーのインスタンスを複数起動した場合)

```bash:実行結果
$ vncserver -localhost

New 'X' desktop is your_hostname:1

Starting applications specified in /home/user/.vnc/xstartup
Log file is /home/user/.vnc/your_hostname:1.log

```

## SSHトンネルを介してクライアント端末からアクセス
SSHトンネルを介してクライアント端末からUbuntuサーバーにアクセス出来ることを確認します。ここでは、事前にUbuntuサーバーとクライアント端末間でSSH接続の設定が出来ているものとします。このコマンドの意味は、クライアント端末の59000番へのアクセスがSSHを解してUbuntu端末の5901番ポートに転送(ポートフォワード)されることを意味しています。ここでは、クライアント端末の`59000`番ポートを使用しましたが、環境によっては、既に使用済みの可能性も有ります。確認方法は`lsof`コマンドを用います。未使用の場合、以下のコマンドを実行しても何も表示されません。

```bash:ポートが使用済みか確認
sudo lsof -i:59000
```

ここでUbuntuサーバー側のポート番号(例では`5901`)について、VNCサーバーの再起動処理の説明部分で、`:1`の番号に注目することを述べました。もし、`:2`や`:3`の場合は、各々`5902`、`5903`となります。これらは、ディスプレイポートと呼ばれており、サーバーインスタンスを区別する目的で付与されます。

```bash
ssh -L 59000:localhost:5901 -C -N -l user your_server_ip
```

その他のオプションの解説は参考記事で詳しく解説されているので、ここでは割愛します。

## クライアント端末から接続
MacでFinderアプリを起動し、`command + K`を打鍵します。以下のウィンドウが表示されます。VNC接続の接続先として`localhost:59000`を指定します。

![リモート接続.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/d8b5703b-f0e0-010b-0ba8-1f7a175a2b93.png)

## ログインパスワードの入力
接続に成功すると以下の様にパスワードの入力が求められます。最初に設定したログインパスワードを入力します。

![リモート接続2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/84f1cf25-623f-aa13-7681-258391f01e57.png)

## 接続完了
接続に成功したら初回接続のみ、以下の様なダイアログが表示されます。ここでは`デフォルト設定を使用する`をクリックします。

![初回起動.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/d423aac9-50ca-db18-6cbc-a727b80f5866.png)

接続設定が完了しました。`CentOS`ライクなUIですが、無事起動しました。筆者がリモート接続専用のXWindowsシステムをセットアップしていたことが理解出来たのは、設定を終えた後でした。。。:scream: :scream_cat:

![デスクトップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/fc1c289a-e170-7766-cd2d-7b566ba4f5a1.png)

ウィンドウ解像度が低いと感じだ場合は，一旦サーバインスタンスを終了し，以下の様に設定を変更します．

```bash
sudo vim /usr/bin/vncserver
```

`Default configuration of the TightVNC Server:`を探します．そして`$geometry`を変更します．筆者は以下の様に設定しました．

```perl
# Default configuration of the TightVNC Server:

# $geometry = "1024x768";
$geometry = "1920x1080";
```

* 参考

http://extstrg.asabiya.net/pukiwiki/index.php?VNC%20%B2%F2%C1%FC%C5%D9%A4%CE%CA%D1%B9%B9

# システムサービス化
systemdサービスとして実行するようにします。こうすることで、サーバーを再起動した場合でも、確実にVNCサーバーが起動するように設定出来ます。

## ユニットファイルを作成
`/etc/systemd/system/vncserver@.service`というファイルを作成します。

```bash
sudo touch /etc/systemd/system/vncserver@.service
```

作成したら、中身を以下の様に編集します。解像度を1920x1080、24ビットカラーとしました。
:warning: `User`,`Group`,`WorkingDirectory`,`PIDFile`の<font color="red">user</font>は環境に合った価を設定して下さい．

```bash
[Unit]
Description=Start TightVNC server at startup
After=syslog.target network.target

[Service]
Type=forking
User=user
Group=user
WorkingDirectory=/home/user

PIDFile=/home/user/.vnc/%H:%i.pid
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1920x1080 -localhost :%i
ExecStop=/usr/bin/vncserver -kill :%i

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

## ユニットファイルを認識させる
編集が完了したら、ユニットファイルを認識させます。以下のコマンドを実行します。

```bash
sudo systemctl daemon-reload
```

## ユニットファイルを有効化
ユニットファイルを有効にします。以下のコマンドを実行します。

```bash
sudo systemctl enable vncserver@1.service
```

:warning: @記号に続く`1`は、サービスが表示される表示番号を示します。本記事の環境では、デフォルトの`:1`です。

<details><summary>実行結果</summary><div>

```bash
$ sudo systemctl enable vncserver@1.service
Created symlink /etc/systemd/system/multi-user.target.wants/vncserver@1.service → /etc/systemd/system/vncserver@.service.
```
</div></details>

## VNCサーバーの実行中インスタンスを停止
現在実行中のVNCサーバーインスタンスを停止します。

```bash
vncserver -kill :1
```

## systemdサービスの開始
以下のコマンドを実行し、systemdサービスとして起動します。完了後、再度リモート接続出来るか確認します。

```bash
sudo systemctl start vncserver@1
```

## 起動確認
以下のコマンドで起動を確認出来ます。

```bash
sudo systemctl status vncserver@1
```

<details><summary>実行結果</summary><div>

```bash
$ sudo systemctl status vncserver@1
● vncserver@1.service - Start TightVNC server at startup
   Loaded: loaded (/etc/systemd/system/vncserver@.service; indirect; vendor preset: enabled)
   Active: active (running) since Sun 2021-07-18 16:05:34 JST; 58s ago
  Process: 6750 ExecStart=/usr/bin/vncserver -depth 24 -geometry 1920x1080 -localhost :1 (code=exited, status=0/SUCCESS)
  Process: 6737 ExecStartPre=/usr/bin/vncserver -kill :1 > /dev/null 2>&1 (code=exited, status=2)
 Main PID: 6763 (Xtightvnc)
...
```

</div></details>

# SSHトンネルも永続化
ものは序でと、SSHトンネルの永続化も行います。接続毎にsshコマンドを実行することは非常に煩雑ですので、良い方法はないかと探っていると`autossh`というコマンドを実行すると良いとのこと。正しい、デフォルトではMacにインストールされていないので、ここではHomebrewを用いてインストールします。

## autosshのインストール
Homebrewを用いてインストールします。

```bash
brew install autossh
```

## トンネル永続化の実行
以下のコマンドを実行します。`ssh`の部分を`autossh -M 0 -f`に置き換えただけです。(`-M 0`はモニタポートオプション0指定で良い様です。`-f`はバックグランドで実行)

```bash
autossh -M 0 -f -L 59000:localhost:5901 -C -N -l user your_server_ip
```

終了する場合は以下のコマンドを実行します。

```bash
killall autossh
```

トンネルを終了した後、接続を試みると以下の様なダイアログが表示されます。

![トンネルオフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/2cd2fc6a-f4d7-0c48-500b-9f4041a682b7.png)

トンネルを再度有効化してログインした結果、無事再ログイン出来ました。
![再ログイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/9fde1688-626f-82d8-d45e-7602e1f04e1a.png)

## 2021/8/9追記: 再起動後も自動的にSSHトンネルを確立
以下のスクリプトを作成しました。

```bash
#!/usr/bin/env bash

sleep 180
autossh -M 0 -f -L 59000:localhost:5901 -C -N -l user your_server_ip
```

再起動後、自動実行される様にCronジョブを追加します。

```bash:Cronファイルの編集
crontab -e
```

```bash:追記した結果
$ crontab -l
TERM=xterm
@reboot スクリプトファイルのパス
```

# まとめ
本記事ではMacをクライアント端末とし、Ubuntuサーバーにリモート接続するための環境構築を行いました。CentOSライクなXWindowシステムが構築され、無事SSHトンネルを経由して接続出来ました。構築を進める過程で、ディスプレイポートの説明を見落としており、なかなか接続出来ずに悶々し、時間を要しました。。。:scream: マニュアルは注意して読まないと思わぬ落とし穴にはまってしまうことを改めて痛感しました。。。(反省)

# Reference
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-20-04-ja

https://www.ipentec.com/document/linux-vnc-firewall-setting

http://yebisupress.dac.co.jp/2017/12/27/ssh-port-forward-for-mac/

https://qiita.com/tukiyo3/items/6a64037117a5488ade78