ダイキのアプリ開発ナレッジ

アプリ開発のナレッジを掲載します

Next.jsのSSG(Static Site Generation)に関する4パターンの整理

Next.js は基本的にデフォルトでビルド時にHTMLを事前生成する
ビルド時にDBからPre-FetchをしてHTMLを事前生成する方式とアプリ運用時のサーバーアクセス時にDBからHTMLを生成する方法が大きく4種類あるので整理する

SSGはStatic Site Generationの略でユーザーに渡す情報は基本的には静的データを渡そうというコンセプトのもとに作られたアプリがユーザーにデータを渡す仕組みである
従来のデータ配信方式ではDBに格納された情報を毎回動的にHTMLにレンダリングして渡していたが、SSGで実装されたアプリでは一度HTMLにレンダリングされた情報は静的コンテンツにしておいて次回のアクセス時には静的コンテンツとして配信される
このHTMLにレンダリングするタイミングの違いによってSSGは以下の4種類のパターンに分類される

SSGについて例えを出すならば今までは飲食店で注文を受けたらその都度料理していたが、開店前に作り置きを作っておいて注文を受けたらそれを出すようなものです
また飲食店は新規メニューのオーダーも都度受け付けていて新規メニューの注文があればその場で料理を行って提供し、その後は作り置きを提供するような仕組みになっています

ISRはIncremental Static Regenerationの略で最新情報をHTMLにレンダリングしておいて静的コンテンツにしておく技術である

ちなみにややこしい話ですがSSRという単語もあって、こちらはServer Side Renderingの略でHTMLは従来クライアント側で生成していたものをサーバ側で作成して渡すようにしたことにあえて名前がついたものになっています
SSRについて例えを出すならば今までコープで食材だけもらって料理は自宅でするのが当たり前だったが生活様式が変化してきてUserEatsを使う人が増えたので"出前"という言葉がはやり始めたみたいな状況です

1.SSG

DocumentやHelpなどのように「完全に静的なページ」
SEOは特に意識しない
代表的なものとしては Index ページがこの実装にあたる場合が多いと思われる
あとはDocumentやHelpページ


2.SSG + Prefetch

ビルド時にデータベースから取得してきた情報を事前にHTMLにレンダリングして静的データとしておくパターンです
Googleクローラーに読み込まれるため、SEO対策に有効です
使われるページの例としてはブログページや商品一覧などが考えられています
ただしそのままだとビルド時の情報のみ使用されるため最新情報を反映させ合たい場合は別途対策が必要です
最新情報を取得する場合にはISRが必要になり、基本的にはISRをセットで利用する場合が多いと思われます
ISRを加えた2.1のパターンがNext.jsで一番よく実装されるであろうと考えられます

2-1. SSG + Prefetch + ISR

Next.jsはビルド時の情報が使われてその後情報が更新されません
後々情報を更新したい場合はISR(DBの最新データで静的サイトを作り直す技術)を使って更新します。
ビルド時にデータを事前にレンダリングするだけでなく、ビルド以降に作成・更新された最新情報に関してもHTML事前レンダリングが実行されて(初回アクセスがトリガー)グーグルのクローラーに分析してもらえるようになり、最新の情報にもSEO対策が施されます


3.SSG + Client side fetching

SEOを意識する必要はないが、最新情報を取得したいページに利用されるパターンです
通常の「create-react-app」(従来のウェブアプリの実装)と似たようなレンダリングの仕組みになります
Client side fetching(通常のAxiosなどのAPI経由でデータを取得する方法)を使って、その都度バックエンドから取得してきたデータをレンダリングしてページを表示させます。
最新データはHTMLにレンダリングされないために新規作成もしくは更新された情報はDBから情報を取得して毎回レンダリングされる仕様となります
DBから情報を取得しないとレンダリングされないのでグーグルのクローラーは有益な情報は何もないと判断してしまい最新の情報に関してはSEOされることはありません
代表的なものとしてはDashboardやTodoリストなどのようなページです


4.SSG + Prefetch + Client side fetching(useSWR)

データをリアルタイムで作成・更新する必要があって、かつ、最新情報にもSEO対策を施す必要があるようなページに利用されるパターンです
2のパターンとほぼ同様ですが、Client side fetchingを使用することで、データの更新をリアルタイムに反映することができます
ただしこの状態では画面表示においてビルド時の過去データと最新情報に乖離がある場合に過去データが表示されたのちに最新データに更新されるという挙動が起きてしまうので、以下の最新データから静的コンテンツを作成しておくISRと組み合わせて使う実装が実用的である

4-1. SSG + Prefetch + Client side fetching(useSWR) + ISR

Next.jsはビルド時の情報が使われてその後情報が更新されません。
後々情報を更新したい場合はISR(DBの最新データで静的サイトを作り直す技術)を使って更新します
ビルド時にデータを事前にレンダリングするだけでなく、ビルド以降に作成・更新された最新情報に関してもHTML事前レンダリングが実行されて(初回アクセスがトリガー)グーグルのクローラーに分析してもらえるようになり、最新の情報にもSEO対策が施されます
初回アクセス以降は事前レンダリングされた最新情報のHTMLが配信されるためISRを使用しないと過去データが表示されたのちに最新データが表示される現象も解決する(具体的にはISRのrevaridateを設定する必要がある)

Next.jsのテスト実行時に.env.test.localの環境変数が読み込まれない時の対処

はじめに

Next.js開発においてAPIエンドポイントのURLを環境変数化した場合にアプリ自体は動くがテストが通らなくなる事案が発生
調べによるとJESTは環境変数を.env.test.localに記載してもうまく読み込んでくれない場合がある模様

環境

OS: Windows 10
node -v: v14.18.0
yarn -v: 1.22.17

package.json

{
  "name": "hoge-project",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest --env=jsdom --verbose",
    "gen-types": "graphql-codegen --config codegen.yml"
  },
  "dependencies": {
    "@apollo/client": "^3.4.17",
    "@apollo/react-hooks": "^4.0.0",
    "@heroicons/react": "^1.0.5",
    "autoprefixer": "^10.4.0",
    "cross-fetch": "^3.1.4",
    "graphql": "^16.0.1",
    "next": "11.1.2",
    "postcss": "^8.3.11",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "setimmediate": "^1.0.5",
    "tailwindcss": "^2.2.19"
  },
  "devDependencies": {
    "@babel/core": "^7.16.0",
    "@graphql-codegen/cli": "2.3.0",
    "@graphql-codegen/typescript": "^2.4.1",
    "@graphql-codegen/typescript-operations": "2.2.1",
    "@graphql-codegen/typescript-react-apollo": "3.2.2",
    "@testing-library/dom": "^8.11.1",
    "@testing-library/jest-dom": "^5.15.0",
    "@testing-library/react": "^12.1.2",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.0.3",
    "@types/node": "^16.11.8",
    "@types/react": "^17.0.35",
    "babel-jest": "^27.3.1",
    "eslint": "7",
    "eslint-config-next": "12.0.4",
    "jest": "^27.3.1",
    "jest-css-modules": "^2.1.0",
    "msw": "^0.35.0",
    "next-page-tester": "^0.30.0",
    "typescript": "^4.5.2"
  },
  "jest": {
    "testPathIgnorePatterns": [
      "<rootDir>/.next/",
      "<rootDir>/node_modules/"
    ],
    "moduleNameMapper": {
      "\\.(css)$": "<rootDir>/node_modules/jest-css-modules"
    }
  }
}

対処法

対処1 Home.test.tsx以外の全てのテストファイルの import 直下に下記環境変数を定義してからyarn testを実行
process.env.NEXT_PUBLIC_HASURA_URL = 'https://xxx.hasura.app/v1/graphql'

こちらはテストをGitHubにアップロードするのをためらってしまうため実用的ではない

対処2 環境変数を各テストケースで毎回読み込む

以下の記事に解決策は書いてあったものその通りの方法を実施した場合ではエラーが出たため自環境では各テストケースで環境変数を読み込む実装とした
Jestを用いたNext.jsのテスト内で環境変数を利用する - Breath Note

プロジェクト直下に
test/setupEnv.ts を作成し、以下を実装

import { loadEnvConfig } from '@next/env'

export const setupEnv = async (): Promise<void> => {
  loadEnvConfig(process.env.PWD || process.cwd())
}

各テストのテストケースで上記のsetupEnvを実行する
XXXXX.test.tsx

// ..........................
import { setupEnv } from "../test/setupEnv" 

//.......................

describe('.................................', () => {
    it ('.................................', async () => {
        await setupEnv()
        // ......................................

こちらは各テストケースに記載する手間はあるが、外部ファイルから環境変数を読み込む形でテストを利用できる

対処3 環境変数をテスト準備時に読み込む

対処2ではhandlersがsetupEnvより前に記述されている場合に環境変数を読み込んでくれないという事案が発生する
解決方法としては await setupEnv() の処理をテスト準備処理をしているコード上部に持ってきてawaitを取り除いてsetupEnv() を行う
こうすることでsetupEnv()を各テストケースに記載する手間も省けるのでこの形が最も良い


XXXXX.test.tsx

// ..........................
import { setupEnv } from "../test/setupEnv" 

setupEnv()

//.......................テスト準備の処理

// 本チャンテストにsetupEnvを記述する必要なし
describe('.................................', () => {
    it ('.................................', async () => {
        // ......................................

Create-React-Appでfound 24 vulnerabilities (8 moderate, 15 high, 1 critical) run `npm audit fix` to fix them, or `npm audit` for detailsの警告が出る対処法

Windows環境でnodeを使うといろいろなところで支障が出るとネットの記事に書いていましたが、例にもれずそのあおりを受けました

環境

  • Windows 10
  • nvm --version 1.1.7
  • node --version v14.18.0
  • npm --version 6.14.15

事象

npx craate-react-app [アプリ名]
のコマンドを打つと、実行はされるが、以下のような警告が発生
気持ち悪いので、どうにかしたい

153 packages are looking for funding
  run `npm fund` for details

found 24 vulnerabilities (8 moderate, 15 high, 1 critical)
  run `npm audit fix` to fix them, or `npm audit` for details

対処

この場合、

npm audit fix

のコマンドでうまくいくケースがおおいらしいが、自分の環境ではうまくいかず、手動でどうにかしないといけない模様

[参考]
npm audit fixでは解決できなかった脆弱性の修正

npm audit

を実行。24個の修正対象パッケージが表示される。以下抜粋

                       === npm audit security report ===


                                 Manual Review
             Some vulnerabilities require your attention to resolve

          Visit https://go.npm.me/audit-guide for additional guidance


  Moderate         Inefficient Regular Expression Complexity in
                  chalk/ansi-regex

  Package         ansi-regex

  Patched in      >=5.0.1

  Dependency of   react-scripts

  Path            react-scripts > webpack-dev-server > yargs > cliui >
                  string-width > strip-ansi > ansi-regex

  More info       https://github.com/advisories/GHSA-93q8-gq69-wqmw

...他多数

  Critical        Prototype Pollution in immer

  Package         immer

  Patched in      >=9.0.6

  Dependency of   react-scripts

  Path            react-scripts > react-dev-utils > immer

  More info       https://github.com/advisories/GHSA-33f9-j839-rf8h


  High            Uncontrolled Resource Consumption in ansi-html

  Package         ansi-html

  Patched in      No patch available

  Dependency of   react-scripts

  Path            react-scripts > @pmmmwh/react-refresh-webpack-plugin >
                  ansi-html

  More info       https://github.com/advisories/GHSA-whgm-jr23-g3j9

....他多数

found 24 vulnerabilities (8 moderate, 15 high, 1 critical) in 1956 scanned packages
  24 vulnerabilities require manual review. See the full report for details.

ここでcriticalになってるimmerを調べる

npm ls immer

すると、依存関係がわかる

project_name@0.1.0 C:\Users\[MyUser]\Documents\Development\ReactTutorial\tutorial
`-- react-scripts@4.0.3
  `-- react-dev-utils@11.0.4
    `-- immer@8.0.1

これはpackage.jsonには記述されていない箇所なので、この依存関係を修正していく
package-lock.jsonの方を修正する(lockの方ね)
immerで検索してヒットした箇所のバージョンを変更する

[修正前]

"immer": "8.0.1",

[修正後]

"immer": "9.0.6",

node-modulesを削除して、

npm install 

を実行

これをエラーがなくなるまで警告が出ているパッケージに繰り返す
パッチがないものもあり、最後まで警告解消できないものもある
気持ち悪いが仕方ない....

npm install 実行後、npm audit実行

                       === npm audit security report ===


                                 Manual Review
             Some vulnerabilities require your attention to resolve

          Visit https://go.npm.me/audit-guide for additional guidance


  High            Uncontrolled Resource Consumption in ansi-html

  Package         ansi-html

  Patched in      No patch available

  Dependency of   react-scripts

  Path            react-scripts > @pmmmwh/react-refresh-webpack-plugin >
                  ansi-html

  More info       https://github.com/advisories/GHSA-whgm-jr23-g3j9


  High            Uncontrolled Resource Consumption in ansi-html

  Package         ansi-html

  Patched in      No patch available

  Dependency of   react-scripts

  Path            react-scripts > webpack-dev-server > ansi-html

  More info       https://github.com/advisories/GHSA-whgm-jr23-g3j9

found 2 high severity vulnerabilities in 1941 scanned packages
  2 vulnerabilities require manual review. See the full report for details.


しかしながら、この状態でまた何らかのパッケージをインストール(npm install redux)すると、package-lockがもとに戻ってまたエラーが出てしまった
本番環境に挙げるときにこの作業するか、Linux環境作ってそこで実行する方がいいのかもと思った......


修正したpackage-lock.jsonは一応どこかに保管して差し替えて使おうと思う(自分の場合はuser直下のprojectsフォルダ直下に格納)
次にCreate-React-Appした際にこのlockファイルにさしえることで今回の手間を削減できるはず

Create-React-Appのコマンド実行で失敗する事案の対処

Create-React-Appのコマンド実行で失敗する事案が発生
(npx create-react-appで"Error: EPERM: operation not permitted, mkdir 'C:\Users\〇〇 ' command not found: create-react-app")
PCのユーザー名にスペースが含まれることが原因っぽかったので、対処法を備忘録

解決法1

npxがキャッシュを作ろうとしているときに半角スペースによって、本来フォルダ作成権限のないところユーザー以下のフォルダに
以下を参考にしたらうまくいくかもと思って実行するも
Running npx globally does not work on Windows when the user folder patch contains a space · Issue #146 · zkat/npx · GitHub

if you want to use current path that has space in username "C:\Users\Firstname Lastname\AppData\Roaming\npm-cache"
you can replace the string after space with "~1"
npm config set cache "C:\Users\Firstname~1\AppData\Roaming\npm-cache" --global

npm config set cache "C:\Users\[半角スペースで区切られる手前のユーザー名]~1\AppData\Roaming\npm-cache" --global

ここで書かれている~1はエイリアスの文字列だったはず(半角スペースで区切られてるユーザー名を補完するワイルドカードだったような気がする)


自分の場合上記でうまくいかなかったが、ここに解決方法が書いてあった
どうやらミドルネームが入るような半角スペースを複数含むユーザー名だと最初の6文字を大文字にしてその後ろに~1をつけるエイリアス名もとれる模様
Running npx globally does not work on Windows when the user folder patch contains a space · Issue #146 · zkat/npx · GitHub

you can replace the string after space with "~1"

@citoreek It's a bit more complicated. You remove all the spaces from the folder name, then you take the first 6 characters of the folder name and postfix it with ~1. Officialy, you should also uppercase it, but I found it doesn't make a difference.

So the full path of my folder was:
C:\Users\Gijs van Dam\AppData\Roaming\npm-cache
the path with the short folder name is:
C:\Users\GIJSVA~1\AppData\Roaming\npm-cache

If you want to be sure, you can use
dir /x in cmd
or
cmd /c dir /x in powershell to see the short file and folder names inside a folder.


複数の半角スペースを含むユーザー名:Gijs van Dam は エイリアス名:GIJSVA~1 に書き換えることで、パスを通すことができる模様
自分の場合はこれで解決した

npm config set cache "C:\Users\[ユーザー名大文字6文字]~1\AppData\Roaming\npm-cache" --global

参考
npx create-react-appで"Error: EPERM: operation not permitted, mkdir 'C:\Users\〇〇 ' command not found: create-react-app" - Qiita



解決法2

以下ではうまくいくが、なぜ通るのかはよくかわからない

1. npm cache clean --force
2. npm install create-react-app --force
3. npm fund
4. npx create-react-app <app-name>

参考
【React】npx create-react-app my-appに失敗したとき ~ PCのユーザー名に空白があった時の対処法 ~ - Qiita

Django WYSIWYG 導入つまづき箇所メモ

はじめに

DjangoでWebアプリを開発しているのですが、WYSIWYG導入で詰まった部分があったので、備忘録です

WYSIWYGとは

テキストフィールドをリッチにできるやつです
TextField()そのままだと文字しか入力できないですが、summernoteというパッケージを入れて設定することで簡単に使えるようになる模様です
参考にしたサイトは以下です。手順もこちらに投げます
【Django】django-summernoteを使ってブログアプリに便利なテキストエディターを構築

ひっかった部分

リンク先サイトの手順追っていくと、なぜかtextfield部分で接続エラーが出ました
[f:id:shinseidaiki:20210216175411p:plain


setting.pyに以下がないのが原因でした

X_FRAME_OPTOPNS = 'SAMEORIGIN'


こちらのサイトにはその手順が載っていました
DjangoへWYSIWYGエディターを導入する手順① - 株式会社CoLabMix


このOptionはいまいちよくわかってないので、今後調べます(Django公式マニュアル)
Clickjacking Protection | Django documentation | Django



これを登録すると接続できました
f:id:shinseidaiki:20210216180141p:plain

今後

markdownも実装したいので、こちらのサイトを参考にして実装していこうと思っています
引っかかる部分があればまたレポートしていきます
【Django】ブログアプリにマークダウン(django-markdownx)を構築しカスタマイズする

Windows標準機能でRaspberry Pi 4B に接続 - SSH編 - PowerShell で公開鍵認証設定

ラズパイのためにクライアント側に余計なソフトを入れたくないということで、
Windows標準機能でラズパイに接続する方法のメモを残しておきます

今回は PowerShell でラズパイに SSHする方法です

また、私の環境ではラズパイのパスワード認証を拒否する設定をしたいので、公開鍵認証の設定方法も書き残します

前提条件
クライアント側: windows 10
サーバー側: Raspbian Buster


手順概要

1. パスワード認証によるSSH接続

WindowsPowerShellを起動(起動に少し時間がかかる)
f:id:shinseidaiki:20200524225021p:plain

以下のコマンドでパスワード認証によるSSH接続を行う

ssh [ログインアカウント名]@[サーバIPアドレス] -p [ポート番号]
例)  ssh pi@raspberrypi -p 12345

※ ポート番号22の場合は省略可

※なお、ラズパイ側がパスワード認証拒否設定をしていると接続はできない
/etc/ssh/sshd_config の PasswordAuthentication no が記載されている場合は直接ラズパイをいじって、PasswordAuthentication no をコメントアウトする

初回接続時、接続を続行するか尋ねられるので、yes と入力する

その後、パスワードを入力すると、接続できる

SSHはこれで接続完了です。次は公開鍵認証の設定をしていきます

2. 公開鍵認証の設定

2.1. 秘密鍵・公開鍵の生成

クライアント側(Windows側)で鍵生成を行うため、ラズパイにログインしている場合は、exitなどでwindows側の操作に戻る

windows側で以下のコマンドを打つ

ssh-keygen

以下の入力項目を入力する

Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\tatib/.ssh/id_rsa): [←任意の格納場所]
Enter passphrase (empty for no passphrase): [←5文字以上のパスフレーズ]
Enter same passphrase again: [←同じパスフレーズ]

※格納場所未入力の場合は C:\Users\tatib/.ssh/id_rsa に鍵が生成される
パスフレーズは鍵のパスワードであり、ユーザーパスワードとは別物であることに注意

エクスプローラーなどで、[上記格納場所]に、id_rsa と id_rsa.pub があることを確認
※ id_rsa秘密鍵なので厳重管理

2.2. 公開鍵をラズパイ側に登録

パスワード認証によりラズパイにログインする

ssh [ログインアカウント名]@[サーバIPアドレス] -p [ポート番号]

①ホームディレクトリに /.ssh ディレクトリを作成し、パーミッションを変更

以下はラズパイ側で公開鍵を初めて設定する場合にのみ実施
既に実施済みの場合は、②へ

cd ~/
mkdir .ssh
chmod 700 .ssh

※ ~/ はホームディレクトリという意味

②公開鍵認証ファイルに公開鍵の内容を追記

まずはラズパイ側のauthorized_keysファイルを開く

nano ~/.ssh/authorized_keys

次は、windowsGUI操作に戻り、2.1で生成した公開鍵(id_rsa.pub)をメモ帳などで開く

ものすごく長い文字列が表示されるので、それを Ctrl + C などで一度コピーする

次に、ラズパイ側で開いたauthorized_keysに上でコピーした文字列をペーストする
※ペーストは右クリックで可能

Ctrl + O で保存し、 Ctrl + X でauthorized_keysファイルを閉じる

これで、公開鍵が登録できました

2.3 ラズパイ側SSH設定

最後に/etc/ssh/sshd_configの設定をいじって、鍵認証を有効化します

sudo nano /etc/ssh/sshd_config

上記コマンドで開いた画面において以下を追記します

#鍵認証の有効化
PubkeyAuthentication yes

変更が終わったら、SSHを再起動

sudo service ssh restart


なお、公開鍵認証の確認が取れた後で、もう一度 /etc/ssh/sshd_config を開き、以下を追記することをお勧めします

#パスワード認証を無効化
PasswordAuthentication no

3. 公開鍵認証によるSSH接続

ssh [ログインアカウント名]@[サーバIPアドレス] -p [ポート番号] -i [秘密鍵格納場所]
例)  ssh pi@raspberrypi -p 12345 -i C:\Users\tatib/.ssh/id_rsa

パスフレーズを入力して接続できればOK

Raspberry Pi 4 Model B 初期設定(リモート接続~セキュリティ強化まで)

ラズパイの初期導入、特にセキュリティ周りは毎回どうやっていたか忘れるので、手順を残しておきたいと思います


手順概要


参考記事

初心者向!Raspberry Pi 最低限のセキュリティ設定【所要時間 30分】 - Qiita
ラズパイでやらなければいけない4つのセキュリティ対策! - Qiita
RaspberryPi 3 デフォルトユーザpiの変更 | そう備忘録
Raspberry Piに安全にSSHログインできる公開鍵認証の設定方法 - HomeThink



1. OSインストール

Raspbianをインストールします。
Raspbianを書き込んだmicroSDをラズパイに差し込んで電源を入れれば自動的にインストールが始まります

※このあたりは公式サイトや他のブログの良い記事がたくさん解説してくれているので、割愛します
公式のセットアップ手順
Setting up your Raspberry Pi - Introduction | Raspberry Pi Projects


なお、私は公式サイトからRaspbian(Raspbian Buster with desktop and recommended software Version:February 2020)をダウンロードして、balenaEtcherでmicroSDに書き込む方法を使いました


2. インストール直後の設定

インストールが成功するとRaspbianのデスクトップが表示され、同時に「Welcome to Raspberry Pi」画面が出現します

案内に従って、「ロケーションの設定」と「パスワードの設定」と「ソフトウェアアップデート」をします。

※これらの設定は後からでも出来ます
※最低限パスワードは設定しましょう

たまに、「モニターの枠黒くなってない? 修正しよっか?」みたいな案内も出てくるので、当てはまる場合はチェックボックスにチェックを入れます。

Wi-Fiの設定」もありますが、有線でつないでいる場合は不要です

ラズベリーパイはWi-Fiのパスワードを平文で保持するので、個人的には有線でつないだ方がいいと思っています

設定が終了すると再起動が促されるので、お好みで再起動する


3. リモート接続ラズパイ側設定(SSHVNC

今後ラズパイをリモートで操作するために、ラズベリーパイの設定をいじります
リモートで操作する予定なんてないよとかいう方は適宜読み飛ばしてください

3.1 リモート接続準備

「Menu > 設定 > Raspberry Pi の設定」を選択します

「システム」タブのブートをCLIに変更
「システム」タブの自動ログインを無効
GUIを起動しているとメモリを消費するらしいです
f:id:shinseidaiki:20200510200904p:plain

「インターフェース」タブのSSHVNCを有効にします
f:id:shinseidaiki:20200510200934p:plain

3.2 xrdpのインストール

今回VNCにおいて、クライアント側はWindowsリモートデスクトップ接続を使用するつもりなので、必要なアプリケーションをラズパイ側にインストールします
※どうやらVNCは平文で、RDPは暗号で通信を行っているようなので、ラズパイのGUIをリモート操作したい場合はリモートデスクトップに軍配が上がるといえそうですね

まず、ターミナルを開きます

とりあえず、おまじない

sudo apt-get update 
sudo apt-get upgrade

xrdpのインストール

sudo apt-get install xrdp 

これでWindowsリモートデスクトップ接続ができるようになります

その後、リモート接続するためにifconfig等でipアドレスを調べて控えておく

ifconfig

Windows端末からラズパイにリモートデスクトップ接続確認をして、操作が出来ればOK
f:id:shinseidaiki:20200510204108p:plain

※ちなみに、Raspberry Pi の設定においてScreen Bankingを有効にしないと接続に成功しても操作を受け付けなくなる(フリーズする)ようです。私はここでかなり悩みました

一度、再起動して。次はユーザー設定を行っていきます


4. ユーザー設定

ここからの設定はリモート端末からラズパイを操作している前提で話します

rootユーザーやpiユーザーは初期のユーザー名とパスワードが公開されちゃっているのでデフォルト状態で放っておくのは脆弱性のカタマリといえるでしょう

他の記事を見る限り、この対処法としては、rootユーザーはリモート端末から操作できないユーザーにして、piユーザーはユーザー名を変更するというのが一般的のようです。

なので、この記事でもその方針で行きます

まず、TeraTermなど適当なソフトウェアを使用して、クライアント側からラズパイにSSHで接続します


4-1. rootユーザー設定
rootユーザーはパスワードが設定されていないので、設定します

sudo passwd root


SSHでのrootのログインを禁止するために、/etc/ssh/sshd_configを編集します

sudo nano /etc/ssh/sshd_config

で、編集画面を開き、

PermitRootLogin no

を追記して、保存します。rootユーザーに関しては以上です。

4-2. 仮ユーザー設定

他のユーザーでないとユーザー名は変更できないようなので、仮ユーザーtmpを作成します

sudo adduser tmp

パスワードとその他情報の設定を促されるので入力します


tmpユーザーに管理者権限を付与

sudo gpasswd -a tmp sudo

tmpがsudoグループに追加されたのを確認して、再起動

sudo reboot

※piユーザーの自動ログインを無効にしていない場合は無効にします

4-3. ユーザー名変更

再起動後、tmpユーザーでログインします

whoコマンドでログインユーザーを確認すると

who

ユーザー名 接続端末 ログイン時刻(接続端末IP)
tmp pts/0 yyyy-MM-dd hh:mm (192.168.x.xx)
が表示されるので、ユーザー名にpiユーザーがいないことを確認します

piユーザがいないことが確認出来たら、ユーザー名を変更します
※newpiは任意のユーザー名

sudo usermod -l newpi pi

tmpユーザーはsudoが初めてなので、sudo初回実行時のメッセージが出て来ると思います
よく読んでからパスワードを入力しましょう

ユーザーのホームディレクトリはまだ pi のままなので変更します

sudo usermod -d /home/newpi -m newpi

グループもpiからnewpiに変更します

sudo groupmod -n newpi pi

これでpiユーザーの変更が出来ました

後は再起動して、tmpユーザーを削除すればユーザー設定は完了です

4-4. 仮ユーザーの削除

tmpユーザーを残したままだと問題があるので、削除します

再起動後、newpiでログインします

userdelコマンドでホームディレクトリごとユーザーを削除します

sudo userdel -r tmp

※ところで -r はホームディレクトリだけじゃなくメールスループも削除するオプションのようですね

これでユーザー設定は完了です


5. ネットワーク設定

基本的にラズパイはリモートでいじることが多いのでネットワークの設定を強化します


5.1 IPアドレスの固定(非推奨)
デフォルトだと動的にIPアドレスが変更されるので、IPを固定すると便利だったりします
※動的IPでも変更までの期間がわりと長いので、固定する必要性は微妙だったりもします

固定IPを割り当てる場合は/etc/dhcpcd.confを編集する

sudo nano /etc/dhcpcd.conf

で設定ファイルを開き、以下を追記する(有線の場合)

interface eth0
static ip_address=192.168.x.xx/24
static routers=192.168.x.x
static domain_name_servers=192.168.x.x

再起動後、固定したIPでつながればOK
※無線の場合はinterface eth0をinterface wlan0に変更

5.1 ホスト名の設定

IPアドレス剥き出しだと管理上煩雑になるので、ホスト名でアクセスできるようにします
といっても設定はかなり簡単です。
GUIであれば「Menu > 設定 > Raspberry Pi の設定」
CUIであれば 「raspi-config > 2 NetWork Options > N1 Hostname」 で設定できます

初期のホスト名は raspberrypiとなっているので、好きな名前に書き換える


GUIでの設定の様子
f:id:shinseidaiki:20200524215308p:plain

CUIでの設定
f:id:shinseidaiki:20200524215640p:plain

再起動後、設定が反映されるので、ホスト名を使ってアクセスできるか確かめる

リモートデスクトップ接続でのアクセス確認
f:id:shinseidaiki:20200524220350p:plain

他の記事だと .local をケツに付ける必要があると書いているものがありますが、
今は .local 抜きでも接続できるようになっているみたいですね

5.2. 公開鍵認証

SSHは公開鍵認証の仕組みがあるので、決まった端末からしかラズパイに接続出来ないようにしてセキュリティを上げることにします

秘密鍵と公開鍵はいろいろな方法があるようですが、今回はTeraTermの機能で作ることにします。

[クライアント側操作]
①クライアントで起動しているTeraTermのメニューより 設定 > SSH鍵生成 を選択

RSAとビット数が2048であることを確認し、生成ボタンをクリック

パスフレーズを登録する(ユーザーパスワードとは別物であることに注意)

④公開鍵と秘密鍵をそれぞれクライアント端末の任意の場所に保存
秘密鍵は大事に保管すること

[サーバー側操作]
⑤ホームディレクトリに /.ssh ディレクトリの作成し、パーミッションを変更

cd ~/
mkdir .ssh
chmod 700 .ssh

⑥公開鍵の内容を公開鍵認証ファイルを作成して追記します
※他の端末からラズパイが受け取る公開鍵のデータは authorized_keys という名称のファイルで一括保管する仕様になっているみたいです

nano ~/.ssh/authorized_keys

クライアント側で保存している公開鍵ファイル”id_rsa.pub”をテキストエディタで開き、上記コマンドで開いた画面にコピー&ペーストします
TeraTerm上で右クリックすると貼り付けられます

⑦公開鍵認証ファイルのパーミッションを変更します

chmod 600 ~/.ssh/authorized_keys

公開鍵認証でラズパイに接続確認して、接続できればOK

TeraTermにおいて公開鍵認証でSSHする方法
SSH認証画面において、パスフレーズは③で設定したものを入力
認証方式: RSA/DSA/ECDSA/ED25519鍵を使う を選択
秘密鍵の格納場所を選択

5.3 パスワード認証無効化&ポート番号変更

最後の仕上げとして、秘密鍵を持っている端末しかSSH接続が出来なくなるようにパスワード認証を無効化します

また、ポート番号をデフォルトの22から別の値に変更することでよりセキュリティを強化します

/etc/ssh/sshd_configの設定をいじります

sudo nano /etc/ssh/sshd_config

上記コマンドで開いた画面において以下を追記します

#ポート番号の変更
Port xxxxx (xxxxxには0~65535番目の任意の数値)

#鍵認証の有効化
PubkeyAuthentication yes

#パスワード認証を無効化
PasswordAuthentication no

変更が終わったら、SSHを再起動

sudo service ssh restart

設定が反映されていればOK。

以上でラズパイの初期設定は終わりです


終わりに

とりあえず、これで一通りの設定は完了です

次は、microSDが壊れた時のためのバックアップをとりたいと思います


メモ

リモートデスクトップ接続するにはScreen Bankingを有効にしないといけない