RHEL 8 で TFTPサーバーをインストール

# 1.環境
RHEL 8.2を使用しました。

```
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.2 (Ootpa)
```

# 2.インストール

インストールは、以下の通りです。

この例では、TFTPのサーバーだけでなく、後で動作を確認するため tftpのクライアントコマンドも導入しています。

```
$ dnf -y install tftp-server tftp
```
`tftp-server` : TFTP server 
`tftp` : TFTP クライアントコマンド (アクセス確認用に使います）


# 3.操作

Linux のサービス･マネージャーである [systemd](https://www.freedesktop.org/software/systemd/man/systemd.html#) は、サービスを11の異なる`Unit`という単位に分けて、ブートアップ時や、メンテナンス時のサービス間の依存関係をコントロールしています。

TFTPサーバーは、[socket](https://www.freedesktop.org/software/systemd/man/systemd.socket.html#) `Unit` です。

socket `Unit`には、ソケットで受け取ったリクエストを処理をするための [service](https://www.freedesktop.org/software/systemd/man/systemd.service.html#) `Unit`が必ず存在する事になっています。
`tftp.socket` の場合は、`service`として `tftp.service` が存在しており、この二つはペアになっています。

`tftp.service`は、`tftp.socket` によって、自動的に起動されるので、起動･停止は`tftp.socket` だけに注目すれば問題ないです。

## 3.1.起動

```
$ systemctl start tftp.socket
```

## 3.2.停止

```console
$ systemctl stop tftp.socket
```

## 3.3.状態の確認
```console
$ systemctl status tftp.socket
```

## 3.4.自動起動設定

```
$ systemctl enable tftp
Created symlink /etc/systemd/system/sockets.target.wants/tftp.socket → /usr/lib/systemd/system/tftp.socket.
$
```
自動起動登録時の動きとしては、`/etc/systemd/system/sockets.target.wants/` の下に `tftp.socket` (へのシンボリックリンク) が追加されます。

これにより`tftp.socket`が他の `sockets.target.wants` 配下に登録された socket サービスと同様に自動起動してくるようになります。
## 3.5.自動起動設定の確認

TFTPは、`tftp.service` と `tftp.socket` の2つの`ユニット`で構成されています。

`tftp.service` は、`tftp.socket` に依存してた`ユニット`なので、`tftp.socket` が、`enabled` になっていれば OKです。
`tftp.service` は、`indirect` でOKです。

```
$ systemctl is-enabled tftp.socket
enabled
$ systemctl is-enabled tftp.service
indirect
$
```

## 3.6.アクセス確認

tftp のルートディレクトリは `/var/lib/tftpbood/` とちょっと変わったパスになります。

テスト用のファイル `/var/lib/tftpbood/test.txt` を作成します。

```
$ cat << EOF > /var/lib/tftpboot/test.txt
this is test
EOF
```

`tftp`コマンドを使用して、作成したファイルを取得してみます。

```
$ tftp localhost -c get test.txt
$ ls -ltr | grep test.txt
-rw-r--r--. 1 root root   13 Sep 27 12:57 test.txt    # test.txt が取得できています。
$
```

# 4.firewalldの設定

TFTPにサーバー外からアクセするには、デフォルトで起動している Firewalldに穴を開けてあげる必要があります。

## 4.1 現在の設定の確認

RHEL8を入れたばかりの素の状態であれば、ここは読み飛ばして「tftp 用の穴を開ける」に飛んでも大丈夫です。
Firewallの設定は、NIC(Network Interface Card) 毎に「Zone」というグループを作って管理されています。


`firewall-cmd --get-active-zone`で、現在アクティブなゾーンを確認します。

```
$ firewall-cmd --get-active-zone
libvirt
  interfaces: virbr0       　# これはdefault で動いている仮想 NIC。今回は関係無い。
public
  interfaces: ens224 ens256       # ens224 と、ens256 はこのサーバーの NIC
$
```

この例では、 `ens224` と `ens256`の両方の NICが `public`ゾーンに所属しています。

とりあえず、穴あけ設定が必要なのは、NICの所属している「`public`」のゾーンであると記憶します。
次は「`public`」に設定されている「`サービス`」を確認します。

```
# public の firewall の service を確認する。
$ firewall-cmd --list-services --zone=public
cockpit dhcpv6-client ssh # 「cockpit」「dhcpv6-client」「ssh」3つのサービスが登録されている。
```
※`cockpit`とは、RHEL8 が持っている Webインターフェイスで OSの状態を確認できる管理コンソールです。

tftp 用の穴が開いてないようなので、tftp用の穴を開けます。

## 4.2 TFTP用の穴を開ける

`public`ゾーンに、TFTP用の穴を開けます。

```
$ firewall-cmd -add-service=tftp --zone=public --permanent

Memo:
-zone を指定しない場合は、[firewall-cmd --get-default-zone]で返ってくる default の zone に設定される。

# 新しい設定を永続化させます。
$ firewall-cmd --reload      
```


# 5.[補則] tftp.socket と tftp.service の関係

TFTP は、`tftp.socket` と `tftp.service`　で構成されています。

`tftp.socket`は、ソケットの接続を待ち受け、通信があると`tftp.service`を処理のために起動します。

この2つはそれぞれ`socket` と `service`として別々の構成ファイルを持っています。

`tftp-server` インストール後に、パッケージがファイルを配置する `/usr/lib/systemd/system` を確認すると `tftp.sockcet` と `tftp.service` という2つの [`Unitファイル`](https://sites.google.com/site/kandamotohiro/systemd/man-systemd-unit-no-yi)が出来ていています。

```
# ls -ltr | grep tftp
-rw-r--r--. 1 root root  112 Aug 13  2018 tftp.socket
-rw-r--r--. 1 root root  189 Aug 13  2018 tftp.service
#
```



`tftp.socket` の内容は以下になります。
自動起動を ON にすると、`socket.target.watns` 配下に、この socket unit へのシンボリックリングが作られる(=OSブート時に自動起動される) ように設定が書かれています

```/usr/lib/systemd/system/tftp.socket
[Unit]
Description=Tftp Server Activation Socket

[Socket]
ListenDatagram=69

[Install]  # systemctl enable/disable (自動起動)設定時の動き
WantedBy=sockets.target  # sockets.target.wants ディレクトリに、この設定へのシンボリックリンクを作成する                 
```


`tftp.serivce` の内容は以下になります。`tfp.socket` の起動が前提になっている事がわかります。

```/usr/lib/systemd/system/tftp.service
[Unit]
Description=Tftp Server
Requires=tftp.socket　　   　# このユニットが前提とするユニット。tftp.socket が起動しなければ tftp.service も起動しない。
Documentation=man:in.tftpd

[Service]
ExecStart=/usr/sbin/in.tftpd -s /var/lib/tftpboot      # /var/lib/tftpboot がルートディレクトリ
StandardInput=socket

[Install]
Also=tftp.socket         # このユニットが install/uninstall もしくは enable/disable 時に同様に処理されるユニット
```   
[注意] これらの `Unitファイル` は直接編集すると、パッケージのアップデート時に上書きされてしまう可能性あるため、`/usr/lib/systemd/system` にあるファイルを `/etc/systemd/system` にコピーして編集を行います。

もし同じ名前のファイルが `/etc/systemd/system` にある場合はそちらが優先して読み込まれるそうです。