Intel NUC に Arch Linux をインストールする

# はじめに
サーバー立てたいと思ってもSynology NAS の DSM で大抵出来てしまって、それで十分なのですが、
「Linux使えないからそれ使ってるんでしょ？(被害妄想)」って思われるのが悔しかったので、Linuxを用意することにしました。
基本的に管理はSSHで作業することを考えているので、
この記事ではインストールからssh接続出来るところまでを目標とします
また、この記事では Arch 以外の作業を行ってるPCは Windows 10 想定です。
Arch LinuxはWikiが充実しており、インストールについても詳しくwikiに載っています。
この記事の内容とArchWikiの内容に差が大きくあった場合、間違いなくArchWikiの方が新しいので、この記事はArchWikiの補助程度に捉えてください。
インストールする際はArchWikiを第一に参考にしましょう。
インストール中のスクリーンショットは直撮りで見にくいです。

この記事は以下二つを特に大きく参考にしました。
参考: [ArchWiki - インストールガイド](https://wiki.archlinux.jp/index.php/%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%82%AC%E3%82%A4%E3%83%89)
参考: [Qiita - Arch Linux インストール俺々式完全版](https://qiita.com/TsutomuNakamura/items/b60518f8788e5e998744)

# デバイス選定

今回選んだNUCはこちらです。
[Intel NUC 8 Rugged ][(https://www.intel.co.jp/content/www/jp/ja/products/docs/boards-kits/nuc/nuc8rugged-nuc8cchk-cchb.html)
自宅にサーバーを置くことの懸念として、電気代とうるさくなることが大きな理由だったのですが、CPUのTDPが6Wと低くファンレスでファンがうるさいという心配が無くそれが決め手となりました。
Intel NUCキットというとメモリ, ストレージ, OSを自分で用意する必要がある場合が多いですが、こちらの製品はメモリははじめから4GB搭載されており、
ストレージについては64GBのeMMCが搭載されていました。
ストレージについてはさらにM.2接続のSSDを追加することが出来ます。
eMMCというとただ廉価なストレージという印象が先行しますが、多くの場合HDDよりも高速です。
また、eMMC最大の長所としてHDDよりはもちろん、SSDよりも消費電力が低いです。
消費電力を抑えたいサーバー用途としては割と適任だと思います。
64GBもあれば今回は十分なので、SSDは追加せず、eMMCにインストールします。

# Arch Linux のインストール
## USBメディアの作成
参考: [ArchWiki - USB インストールメディア](https://wiki.archlinux.jp/index.php/USB_%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2#USBWriter_for_Windows)

まずはUSBインストールメディアを作ります。
WSLの `dd` を使ってできないか模索したのですが、うまくいかなかったので
`USB Writer for Windows` を使用しました。
インストール不要で使えます。

## NUCの下準備
まず、NUCのUEFI画面に入ります
NUCに NUCの電源を入れてスプラッシュ画面が表示されたらF2キーを押します。

UEFIが起動したら[bootタブ] → [Secure boot] → [Disabled]を選択

![IMG_4956.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/7ef15545-0de9-6478-6ceb-765e34d30ecb.jpeg)

Secure Boot をオフにする
参考: [Intel - Support](https://www.intel.co.jp/content/www/jp/ja/support/articles/000038401/intel-nuc/intel-nuc-kits.html)

また、UEFI Boot はEnabled、Legacy Boot はDisabled になっていることを確認します。
これらが上記になっていない場合BIOSブートします。
BIOSブートでも問題ありませんが、この記事ではUEFIブートでインストールすることを前提にします。
F10を押して保存して再起動します。
1度電源を落としてUSBインストールメディアを接続して起動します。
つける時と同様に電源ボタンを短く押せば電源を落とせます。

次の画面が表示されれば、UEFIブートに成功しています。
![IMG_4957.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/461dfb60-c816-f3c4-957c-c9defdf007ac.jpeg)
このboot画面でeキーを押して末尾に `nomodeset` を追記して Enter で起動します。
(末尾には `ctrl + e` か、 `End` キーを押せば一発で飛べます)
`nomodeset` を付け足さないと、画面が真っ暗で何も表示されませんでした。
参考: [Arch Linuxとの格闘　第２ラウンド](http://tramedy.web.fc2.com/bun/archmem02.html)
もし、画面真っ暗で起動してしまった場合、何も見えない中でも `shutdown -h now` と入力してEnter押すとシャットダウン出来ます。
画面が映っていないだけで、正常に起動出来ています。
まだ、何もインストールしていないので、普通に本体の電源ボタンを押して電源を落としても良いでしょう。

USBからArch Linuxが起動したら何もせずともrootとしてログインされることでしょう。
ここでまた

```shell-session
# ls /sys/firmware/efi/efivars
```

を実行して、UEFIモードで起動出来ているか確認出来ます。

## パーティションの設定

参考: [ArchWiki - EFI システムパーティション](https://wiki.archlinux.jp/index.php/EFI_%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%B3#GPT_.E3.81.A7.E3.83.91.E3.83.BC.E3.83.86.E3.82.A3.E3.82.B7.E3.83.A7.E3.83.B3.E3.81.95.E3.82.8C.E3.81.9F.E3.83.87.E3.82.A3.E3.82.B9.E3.82.AF)

> UEFI ブートではいつでも GPT を使うことが推奨されます。

> 2GB 以上の物理 RAM を持っているなら、スワップパーティションがないほうが一般的に良いパフォーマンスを発揮すると思われます。
[ArchWiki - パーティショニング](https://wiki.archlinux.jp/index.php/%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%8B%E3%83%B3%E3%82%B0#GPT_.E3.81.8B_MBR_.E3.81.AE.E9.81.B8.E6.8A.9E)

とあるので、パーティションテーブルはGPT、swapパーティションは作りません。

|マウントポイント|パーティション|  パーティションタイプ  |容量   |
|:-------------|:-----------|:----------------------|:------|
|`/mnt/boot`   |`/mmcblk0p1`|EFIシステムパーティション|512MB  |
|`/mnt`        |`/mmcblk0p2`|Linux filesystem       |残り全て|

でパーティションを作ります。

```shell-session
# fdisk -l
# gdisk /dev/mmcblk0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/13a81e6c-40d7-fa3e-d3a8-9f16bbcf1bc2.png)

eMMCのストレージは `mmcblk0` と表示されています。
ここに表示されている `sda` はインストール先のストレージでは無くて、USBインストールメディアです。
もし、SSDを追加した場合はその分表示が変わっているはずなので、読み変えてください。
`n` でパーティションを作成中に

> Hex code or GUID (L to show codes, Enter = '8300'):

と表示されます。ここのコードでパーティションタイプを選択します。
`EFIシステムパーティション` は `ef00`
`Linux filesystem` はデフォルトの `8300`
別のパーティションを作る場合、書いてあるとおり `L` で一覧を表示できるので、それを参考にしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/98af73d4-c704-2ee6-2f00-928a045fae03.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/4415c4b7-54fe-c039-3268-81cbdf6d3c7b.png)

最終確認が出ますので、 `y` で進めて `The operation has completed successfully.` が表示されればOKです。
続いてパーティションが分けられたことを確認して、フォーマット、マウントします。

```shell-session
# lsblk
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/f0af3541-4313-e3d8-a4e9-cfebd8f99bc7.png)

```shell-session
# mkfs.fat -F32 /dev/mmcblk0p1
# mkfs -t ext4 /dev/mmcblk0p2
# mount /dev/mmcblk0p2 /mnt
# mkdir /mnt/boot
# mount /dev/mmcblk0p1 /mnt/boot
```

## ネットワーク設定

```shell-session
# ip link
# ping archlinux.jp
# systemctl start dhcpcd@enp2s0.service
# ping archlinux.jp
# systemctl enable dhcpcd@enp2s0.service
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100313/e75f9384-59bd-85e0-2d96-23197dd27fe9.png)

## 時刻設定

```shell-session
# timedatectl set-ntp true
# timedatectl status
```

[ArchWiki - 時刻](https://wiki.archlinux.jp/index.php/%E6%99%82%E5%88%BB#.E3.82.BF.E3.82.A4.E3.83.A0.E3.82.BE.E3.83.BC.E3.83.B3)

## インストール

本当に必要最低限のものだけインストールします。
これだけでは当たり前のように足りないのですが、それらは必要になり次第 `pacman` でインストールします。

```shell-session
# pacstrap /mnt base linux linux-firmware
```

## システムの設定

### fstab
```shell-session
# genfstab -U /mnt >> /mnt/etc/fstab
```

### chroot

```shell-session
# arch-chroot /mnt
```

chroot した後、インターネットに繋がらなくなるので、再度

```shell-session
# systemctl start dhcpcd@enp2s0.service
```

### タイムゾーン

```shell-session
# timedatectl set-timezone Asia/Tokyo
# hwclock --systohc --utc
# timedatectl status
```

### ロケール

```shell-session
# pacman -S vim
# vim /etc/locale.gen
en_US.UTF-8 UTF-8 と ja_JP.UTF-8 UTF-8 のコメントアウトを外す
# locale-gen
# echo LANG=en_US.UTF-8 > /etc/locale.conf
```

### ホスト名

```shell-session
# echo MYHOSTNAME > /etc/hostname
# vim /etc/hosts
```

```/etc/hosts
127.0.0.1	localhost
::1		localhost
127.0.1.1	MYHOSTNAME.localdomain	MYHOSTNAME
```

### rootのパスワード

```
# passwd
```

### ブートローダー

参考: [ArchWiki - systemd-boot](https://wiki.archlinux.jp/index.php/Systemd-boot)

ブートローダーは `systemd-boot` をインストールします。
`GRUB` も比較的使われていると思います。
`GRUB` はUEFI、BIOS共に実行出来ますが、 `Systemd-boot` はUEFIのみです。

#### インストールおよび更新設定

```shell-session
# bootctl --path=/boot install
# bootctl update
# mkdir /etc/pacman.d/hooks
# vim /etc/pacman.d/hooks/systemd-boot.hook
```

```/etc/pacman.d/hooks/systemd-boot.hook
[Trigger]
Type = Package
Operation = Upgrade
Target = systemd

[Action]
Description = Updating systemd-boot
When = PostTransaction
Exec = /usr/bin/bootctl update
```

### ローダー追加と設定

```shell-session
# vim /boot/loader/loader.conf
```

```/boot/loader/loader.conf
console-mode 1
default  arch
timeout  4
editor   no
```

`console-mode 1` はHiDPI対応です。実際に設定してみて、自身の環境で見やすい値を設定してください。
[ArchWiki - HiDPI](https://wiki.archlinux.org/index.php/HiDPI#systemd-boot)

```shell-session
# pacman -S intel-ucode
# vim /boot/loader/entries/arch.conf
```

```/boot/loader/entries/arch.conf
title   Arch Linux
linux   /vmlinuz-linux
initrd  /intel-ucode.img
initrd  /initramfs-linux.img
options root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx rw nomodeset
```

`loader.conf` の `default` で設定した文字列とentriesに追加したファイルの `.conf` を除いた文字列が一致するようにしましょう。
`options` で指定する LABEL や UUID は `lsblk -f` で確認出来ます。
参考: [shioleap blog - ArchLinuxのブートローダーはsystemd-bootが便利](https://shioleap.github.io/blog/Linux/ArchLinux/use-systemd-boot/)
ラベルの設定仕方分からなかったので、UUIDで設定しました。
もし、boot画面でdefaultが別の物になってしまった場合、カーソルを合わせて、 `d` を押す事で切り替え出来ます。

### 再起動

```shell-session
# exit
# shutdown -h now
```

電源が切れたらUSBメモリを抜いて、再起動 user は `root` password は先ほど設定したものを入力してログイン。

### ユーザーの設定

```shell-session
# pacman -S sudo
# useradd -d /home/MYUSERNAME -s /bin/bash -m MYUSERNAME
# passwd MYUSERNAME
# usermod -aG wheel MYUSERNAME
# EDITOR=vim visudo
```

`# %wheel ALL=(ALL) ALL` のコメントアウトを外す

参考: [ArchWiki - Sudo](https://wiki.archlinux.jp/index.php/Sudo#.E7.8F.BE.E5.9C.A8.E3.81.AE.E8.A8.AD.E5.AE.9A.E3.82.92.E8.A1.A8.E7.A4.BA)

# sshの設定

参考: [ArchWiki - Secure Shell](https://wiki.archlinux.jp/index.php/Secure_Shell)
参考: [ArchWiki - SSH 鍵](https://wiki.archlinux.jp/index.php/SSH_%E9%8D%B5)
参考: [Qiita - SSHの公開鍵認証設定をする](https://qiita.com/jinnai73/items/f1822f2e4d567847e215)

```shell-session
# pacman -S openssh
# echo 'AllowUsers MYUSERNAME' >> /etc/ssh/sshd_config
# echo 'PermitRootLogin no' >> /etc/ssh/sshd_config
# systemctl start sshd.service
# ip address
```

これでssh接続出来るようになったはずなので、sshクライアントとなるPCから `ssh MYUSERNAME@192.168.1.x` で接続出来ることを確認。
確認出来たら、切断して

クライアントPCで

```shell-session
> ssh-keygen -t ed25519
> ssh-add ~\.ssh\id_ed25519
> scp ~\.ssh\id_ed25519.pub MYUSERNAME@192.168.1.x:
```

arch に先ほど作成したユーザーでログインするとホームディレクトリ直下に公開鍵があるはずです。

```shell-session
$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ cat ~/id_ed25519.pub >> ~/.ssh/authorized_keys
$ rm ~/id_ed25519.pub
$ chmod 400 ~/.ssh/authorized_keys
$ sudo vim /etc/ssh/sshd_config
```

```sshd_config
PasswordAuthentication no
PermitEmptyPasswords no
```

の行のコメントアウトを外します。

`ChallengeResponseAuthentication` や `Port` などを設定しても良いでしょう。

再度クライアントPCで

```powershell
> code ~\.ssh\config
```

```ssh\config
Host MYHOSTNAME
    HostName 192.168.1.x
    User MYUSERNAME
    IdentityFile ~/.ssh/id_ed25519
    Port 22
```

と設定し、

```powershell
> ssh MYHOSTNAME
```

とすれば、公開鍵認証で、ssh接続できるはずです。

これでついに、NUCからキーボードとHDMIを外せます…

# おまけ

## Windows の SSH

PowerShell で有効化は

```powershell
❯ Get-WindowsCapability -Online | ? Name -Match ssh


Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed

Name  : OpenSSH.Server~~~~0.0.1.0
State : NotPresent

> Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
```

`scoop` や `chocolatey` でもインストールできます。インストールされるのはたぶん[これ](https://github.com/PowerShell/Win32-OpenSSH/releases)
`wsl` でもできるはずですけど、ssh-agentには `ssh-agent-wsl`というものが別途必要になるらしいです。
Windowsの機能として用意され始めたのでこれから先は `Add-WindowsCapability` で入れるのが安定になってくるように思います。

参考: [Microsoft Docs - Windows Server 2019 および Windows 10 用 OpenSSH のインストール](https://docs.microsoft.com/ja-jp/windows-server/administration/openssh/openssh_install_firstuse)

## Windows の ssh-agent

`ssh-agent` の設定はこちらの記事が分かりやすかったです。
参考: [Qiita - Windows 10のssh-agentをコマンド プロンプト、WSL、Git Bashで使ってみた](https://qiita.com/q1701/items/3cdc2d7ef7a3539f351d#cui%E3%81%A7%E8%A1%8C%E3%81%86%E5%A0%B4%E5%90%88)

```cmd
sc config ssh-agent start=auto
sc start ssh-agent
```

ですが、今ならPowerShellで上記コマンドと同じことが以下で出来ます。

```powershell
Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
```

参考: [Microsoft Docs - OpenSSH キーの管理](https://docs.microsoft.com/ja-jp/windows-server/administration/openssh/openssh_keymanagement)

## pacman

- インストール

```shell
pacman -S PKGNAME
pacman --sync PKGNAME
```

- 検索

```shell
pacman -Ss PKGNAME
pacman --sync --search PKGNAME
```

- アップデート

```shell
pacman -Syu
pacman --sync --refresh --sysupgrade
```

- アンインストール

```shell
pacman -R PKGNAME
pacman --remove PKGNAME
```


検索すると省略系ばかりがヒットしてなんて覚えにくいんだって思ってたのですが、
`-h` で見てみると基本的に省略しない形式が載っていて、オプションの意味も分かりやすかったです。
アンインストール時に `pacman -Rns` とする場合があるのも、

```shell
pacman --remove --nosave --recursive
```

の意味なので、キャッシュを残さず、再帰的に依存関係も削除していくのだとわかります。

```shell-session
$ pacman -S -h
usage:  pacman {-S --sync} [options] [package(s)]
options:
  -b, --dbpath <path>  set an alternate database location
  -c, --clean          remove old packages from cache directory (-cc for all)
  -d, --nodeps         skip dependency version checks (-dd to skip all checks)
  -g, --groups         view all members of a package group
                       (-gg to view all groups and members)
  -i, --info           view package information (-ii for extended information)
  -l, --list <repo>    view a list of packages in a repo
  -p, --print          print the targets instead of performing the operation
  -q, --quiet          show less information for query and search
  -r, --root <path>    set an alternate installation root
  -s, --search <regex> search remote repositories for matching strings
  -u, --sysupgrade     upgrade installed packages (-uu enables downgrades)
  -v, --verbose        be verbose
  -w, --downloadonly   download packages but do not install/upgrade anything
  -y, --refresh        download fresh package databases from the server
                       (-yy to force a refresh even if up to date)
      --arch <arch>    set an alternate architecture
      --asdeps         install packages as non-explicitly installed
      --asexplicit     install packages as explicitly installed
      --assume-installed <package=version>
                       add a virtual package to satisfy dependencies
      --cachedir <dir> set an alternate package cache location
      --color <when>   colorize the output
      --config <path>  set an alternate configuration file
      --confirm        always ask for confirmation
      --dbonly         only modify database entries, not package files
      --debug          display debug messages
      --disable-download-timeout
                       use relaxed timeouts for download
      --gpgdir <path>  set an alternate home directory for GnuPG
      --hookdir <dir>  set an alternate hook location
      --ignore <pkg>   ignore a package upgrade (can be used more than once)
      --ignoregroup <grp>
                       ignore a group upgrade (can be used more than once)
      --logfile <path> set an alternate log file
      --needed         do not reinstall up to date packages
      --noconfirm      do not ask for any confirmation
      --noprogressbar  do not show a progress bar when downloading files
      --noscriptlet    do not execute the install scriptlet if one exists
      --overwrite <path>
                       overwrite conflicting files (can be used more than once)
      --print-format <string>
                       specify how the targets should be printed
      --sysroot        operate on a mounted guest system (root-only)

```

```shell-session
$ pacman -R -h
usage:  pacman {-R --remove} [options] <package(s)>
options:
  -b, --dbpath <path>  set an alternate database location
  -c, --cascade        remove packages and all packages that depend on them
  -d, --nodeps         skip dependency version checks (-dd to skip all checks)
  -n, --nosave         remove configuration files
  -p, --print          print the targets instead of performing the operation
  -r, --root <path>    set an alternate installation root
  -s, --recursive      remove unnecessary dependencies
                       (-ss includes explicitly installed dependencies)
  -u, --unneeded       remove unneeded packages
  -v, --verbose        be verbose
      --arch <arch>    set an alternate architecture
      --assume-installed <package=version>
                       add a virtual package to satisfy dependencies
      --cachedir <dir> set an alternate package cache location
      --color <when>   colorize the output
      --config <path>  set an alternate configuration file
      --confirm        always ask for confirmation
      --dbonly         only modify database entries, not package files
      --debug          display debug messages
      --disable-download-timeout
                       use relaxed timeouts for download
      --gpgdir <path>  set an alternate home directory for GnuPG
      --hookdir <dir>  set an alternate hook location
      --logfile <path> set an alternate log file
      --noconfirm      do not ask for any confirmation
      --noprogressbar  do not show a progress bar when downloading files
      --noscriptlet    do not execute the install scriptlet if one exists
      --print-format <string>
                       specify how the targets should be printed
      --sysroot        operate on a mounted guest system (root-only)
```