仕事でLinuxにNFSサーバーを構築し、WindowsからNFSをマウントすることがあったので、その時のメモです。

環境

NFSサーバー側のOSは Ubuntu 18.04 LTS、NFSクライアント側のOSはWindows Server 2019 を使っています。

NFSサーバーのIPアドレス: 192.168.11.21

NFSクライアントのIPアドレス: 192.168.11.31

NFSサーバーのインストールと設定

まずNFSサーバーをインストールして、NFSで共有するディレクトリを作成します。また今回はWindowsクライアントからアクセスする時のユーザーを、常に “nobody” という一番権限の低いユーザーに設定したいと思います。そのためNFSで共有するディレクトリのオーナーに “nobody” ユーザーを設定します。

今回は “/nfs/my-share” というディレクトリをNFSで共有するよう設定したいと思います。

shell

$ sudo apt install nfs-kernel-server -y

$ sudo mkdir -p /nfs/my-share
$ sudo chown nobody:nogroup /nfs -R
$ sudo chmod 744 /nfs -R

次にNFSの共有設定です。NFSの設定は /etc/exports ファイルに記述します。フォーマットは以下の通りです。

/etc/exports ファイルフォーマット

directory machine1(option1) machine2(option2) ...

(option) の部分には以下を設定でき、複数設定する場合はカンマ (“,”) で区切ります。

設定項目option説明
読み書きro(デフォルト) 読み取り専用
rw読み書き可能
ディスク書き込みsync(デフォルト) ディスクへの書き込みが終わるまで応答しない。
async非同期書き込み (ディスクへの書き込みが完了する前に応答)
root ユーザーからのリクエストの格下げroot_squashroot からのリクエストをanonimousユーザーに格下げ する。
no_root_squashroot からのリクエストを格下げしない。
root以外のユーザーからのリクエストの格下げall_squashroot 以外のユーザーからのリクエストも anonimous ユーザーに格下げする。
no_all_squashroot 以外のユーザーからのリクエストは格下げしない。
anonimousユーザーの指定anonuidroot_squash, all_squashが指定された場合に格下げ先となるユーザーID。 デフォルトは nobody ユーザー。
anongidroot_squash, all_squashが指定された場合に格下げ先となるグループID。 デフォルトは nobody グループ。

※「anonimous ユーザーに格下げする」とは、例えばクライアントが root ユーザーとしてアクセスしようとした場合でも、”root_squash” オプションが指定されていれば、NFSサーバー側でユーザーを変換し、”anonuid” オプションで指定されたユーザーでファイルにアクセスさせる、という意味です。

個人的にはセキュリティのために “all_squash” オプションを常に設定した方がよいと思います。anonimousユーザーはデフォルトで nobody ユーザーという一番権限の低いユーザーが設定されているため、このオプションを設定することで、NFSで共有されているファイル以外のアクセスを防ぐことが可能です。

(複数クライアントが接続する場合、ユーザーを分けてファイルアクセスを制御する、という方法もあると思いますが、その場合も個人的にはクライアント毎にディレクトリを分けて、アクセスは常に nobody ユーザーとするのが良いと思います)

というわけで、/etc/exports ファイルに設定を書きます。

shell

$ sudo nano /etc/exports
-----
#以下を追記。 IPアドレスはNFSクライアントのもの。
/nfs/my-share 192.168.11.31(rw,all_squash)
-----

次に、NFSサーバーで使用するポートを固定します。NFSサーバーでは nfs, portmapper, nlockmgr, mountd という4つのプロセスが動作しますが、この内 nfs (2049)、portmapper (111) 以外はポート番号が決まっておらず、Firewallで許可設定することができません。Firewallで範囲指定でポートを許可するのはセキュリティ リスクがあるため、nlockmgr と mountd のポートを固定してしまいます。

shell

$ sudo nano /etc/default/nfs-kernel-server
-----
# 以下を追記
RPCMOUNTDOPTS="--manage-gids -p 32049"
-----

$ sudo nano /etc/modprobe.d/nfs-local.conf
-----
# 以下を追記
options lockd nlm_udpport=32059 nlm_tcpport=32059
-----

これでNFSサーバーの設定は終わりです。最後にFirewallを設定し、NFSサーバープロセスを再起動して設定を反映させます。

shell

# Firewallを設定
$ sudo ufw allow from 192.168.11.61 to any port nfs
$ sudo ufw allow from 192.168.11.61 to any port 111
$ sudo ufw allow from 192.168.11.61 to any port 32049
$ sudo ufw allow from 192.168.11.61 to any port 32059

# NFSサーバーを起動し、OS起動時に自動的に起動するよう設定
$ sudo systemctl start nfs-kernel-server
$ sudo systemctl enable nfs-kernel-server

# 動作確認: 2049, 111, 32049, 32059 が使用されていればOK
$ sudo rpcinfo -p

# 確認できたら、最後にOSを再起動します
sudo reboot

NFS クライアントのインストールと設定

今回はWindows サーバーからNFSサーバーへ接続します。Windowsサーバーの「役割と機能の追加」で、「NFSクライアント」を選択してインストールします。

インストールが終わったら、エクスプローラーを開いて “\\192.168.11.21\nfs\my-share” にアクセスしてみます。問題無ければ、そのままアクセスできるはずです。

NFSのフォルダをドライブレターにマッピングする場合は、以下のコマンドを実行します。

cmd

# YドライブにNFSフォルダーをマッピング
mount 192.168.11.21:/nfs/my-share Y:

ちなみに、今回は常に nobody ユーザーとしてアクセスすることにしたため設定しませんでしたが、NFSサーバー アクセス時のユーザーを指定する場合は、以下の2つのファイルを作成し、フォーマットに従ってユーザー設定を記述します。

%SystemRoot%\system32\drivers\etc\passwd のフォーマット

# 以下のフォーマットでユーザー設定を記述する
# <Windowsユーザー名>:x:<LinuxユーザーID>:<LinuxユーザーID>:<Linuxユーザー名>:<アクセスするNFSフォルダ>:<デフォルトshell>
# 例: Administrator:x:0:0:root:/nfs/my-share/root:/bin/bash

%SystemRoot%\system32\drivers\etc\group のフォーマット

# 以下のフォーマットでグループ設定を記述する
# <Windowsグループ>:x:<LinuxグループID>:<Linuxグループ名>
# 例: BUILTIN\Administrators:x:0:root

転送ブロックサイズの設定

上記の設定で一応NFSサーバーでファイルを共有できるようになりますが、UbuntuとWindowsではデフォルトのファイル転送ブロックサイズが異なっているため、ブロックサイズ以上のファイルを転送しようとすると、転送サイズが合わずにエラーとなります。

このエラーはWindows側では表示されず、普通に表示が終わるため、ファイルを転送したはずなのに後で確認したら転送されてなかった、という事態に陥るため注意が必要です。

エラーはUbuntu 側のsyslog に以下のようなメッセージで書かれています。

shell

$ sudo tail /var/log/syslog
...
RPC:fragment too large(1048576)
...

上記のようなメッセージが出ている場合は、NFSサーバーとNFSクライアントで転送ブロックサイズが合っていないことが原因です。転送ブロックサイズは Windows、Ubuntu それぞれで以下のコマンドで確認できます。

(Windows) cmd

> nfsadmin client
...
読み取りバッファー サイズ               : 1024 KiloBytes
書き込みバッファー サイズ               : 1024 KiloBytes
...

(Ubuntu) shell

$ cat /proc/fs/nfsd/max_block_size
262144

上記から、転送ブロックサイズはデフォルトでWindowsで1MB、Ubuntuで256KBとなっているのがわかります。今回はUbuntu側を 1MB に合わせます。

(Ubuntu) shell

# NFSサーバーを停止
$ sudo systemctl stop nfs-kernel-server

# 転送ブロックサイズを1MBに設定
$ sudo nano /proc/fs/nfsd/max_block_size
-----
# 以下で上書き
1048576
-----
$ exit

# NFSサーバーを起動
$ sudo systemctl start nfs-kernel-server

これでエラーが出なくなり、どんなサイズのファイルでも正常に転送されるようになります。

以上でNFSサーバー、NFSクライアントの設定は完了です。