STERFIELD

Ubuntu✖️Nginx✖️Next.js(SSG)✖️StrapiでWEBサイトの環境を作る

Ubuntu✖️Nginx✖️Next.js(SSG)✖️StrapiでWEBサイトの環境を作る

最近、WordPress以外のCMSへの移行の需要も広がりつつあるというお話を聞きます。
CMSとして80%の圧倒的なシェアを持つWordPressですが、
シェアの大きさゆえに攻撃の対象にもなりやすく、
実際、攻撃を受けてセキュリティの被害に遭うことも少なくありません。
また、多くの機能を実装できるため、実装次第で重くなりやすい特徴もあります。
そういったこともあり、WordPressを使わないCMSへの移行を望む企業さんも増えているようです。

その移行先として注目されているのが、ヘッドレスCMSと呼ばれる種類のCMSです。
WordPressでは、コンテンツの管理とサイトのレンダリングを両方行います。
一方、ヘッドレスCMSでは、コンテンツの管理のみを行い、サイトのレンダリングやジェネレートなどは別のサービスを利用して行います。
そのため、サイトからコンテンツへの攻撃がされにくくなります。
また、コンテンツの数が多くなってもサイトのレンダリングに直接影響しないため、表示速度を上げやすいメリットもあります。

この記事でご紹介する「Strapi」は、Node.jsのヘッドレスCMSとしては人気があります。
ヘッドレスCMSは多くのサービスが提供されていて、CMS選びに迷いますが、
ホスティングサービスを利用しなければ無料で利用でき、
Nodejsの環境があればローカルで始められるので、開発のハードルが低いのが大きな理由でしょうか。

Strapiはコンテントタイプ(WordPressでいう投稿タイプやタクソノミー)フィールドを自由に構成でき、
ユーザのロールなども管理でき、APIもRestAPIとGraphQLから選ぶことができるので、
高い拡張性が特徴です。

この記事では、Strapiでサイトを構築する1つの方法として、
OSをUbuntu、WebサーバをNginx、サイトのジェネレートをNext.js、そしてCMSをStrapiで開発を始める方法を共有します。
ここでは動作するまでのインストールに重点を置き、コンテンツの作成などは省略します。

目次

  1. UbuntuでNginxによるサーバを設定する
  2. Node.jsでNext.jsとStrapiの環境を準備
  3. Next.jsとStrapiでデータを連携する

UbuntuでNginxによるサーバを設定する

Nginxのインストール

参考にさせていただいたサイト: 【Ubuntu Server 22.04】Nginx公式サイトのリポジトリを使用してインストール | VPS Life
↑詳細はこちらのサイトが詳しいです。
この記事ではざっくりと流れだけ触れていきます。

パッケージのインストール

1$ sudo apt update 2$ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring

署名鍵のインポートと確認

1$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ 2 | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null 3$ gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

正しくインポートされると以下が表示されます

1pub rsa2048 2011-08-19 [SC] [expires: 2024-06-14] 2 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 3uid nginx signing key

リポジトリの追加とインストール

1$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ 2http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \ 3 | sudo tee /etc/apt/sources.list.d/nginx.list 4$ sudo apt update 5$ sudo apt install nginx

インストールの確認

nginxのインストールに成功すると、以下のコマンドでバージョンを確認できます。

1$ nginx -v

ufwによるファイアウォール設定とNginxでサーバの設定

ufw によるファイアウォール設定

そのままサーバを開設すると、セキュリティ的に良くないので、ufwを使って開放するポートを制限します。
参考にさせていただいたサイト: ufwの最小限設定について – とりあえずノートがわりに書いてます

ufwを設定するときは、いきなり実行するとSSH接続ができなくなってしまうので、
まずは、ufw status を実行して、Status: inactive であることを確認します。

確認できたら、以下のコマンドを 1つずつ実行して、許可するポートを制限します。

1$ ufw allow 22 2$ ufw allow http 3$ ufw allow https 4$ ufw allow domain

そしてufwを有効化。

1ufw enable

最後に ufw status を実行して、目的のポートが開放されていることを確認します。

1$ ufw status 2 Status: active 3 4To Action From 5 -- ------ ---- 6 22 ALLOW Anywhere 7 53 ALLOW Anywhere 8 22 (v6) ALLOW Anywhere (v6) 9 53 (v6) ALLOW Anywhere (v6)

利用するVPSなどによっては、VPSのコントロールパネルなどで、
別途、ポートの開放が必要です。

Nginxでサーバの設定

ここでご紹介する方法では、Next.jsでジェネレートしたファイルを静的にNginxでサーブし、
それとは別にStrapiでCMSをサーブします。

そのため、静的にサーブするドメインとCMSをサーブするドメインを別々に割り当てます。

Nginxで静的なサーブ

/etc/nginx/nginx.conf を設定して

1server { 2 server_name <サイト用のドメイン名>; 3 4 location / { 5 root /var/www/<Next.jsのディレクトリ>/out; 6 7 index index.html index.htm; 8 } 9 10 error_page 404 /404.html; 11 12 # redirect server error pages to the static page /50x.html 13 # 14 error_page 500 502 503 504 /50x.html; 15 location = /50x.html { 16 root /usr/share/nginx/html; 17 } 18 19}

Strapi用の設定

/etc/nginx/conf.d/default.conf のhttpの設定で以下を設定

1http { 23 include /etc/nginx/conf.d/*.conf; 4 include /etc/nginx/sites-enabled/*; 5}

/etc/nginx/sites-enabled/<Strapi用のドメイン名>

1server { 2 3 listen 80; 4 server_name <Strapi用のドメイン名>; 5 6 # Proxy Config 7 location / { 8 proxy_pass http://127.0.0.1:1337; 9 proxy_http_version 1.1; 10 proxy_set_header X-Forwarded-Host $host; 11 proxy_set_header X-Forwarded-Server $host; 12 proxy_set_header X-Real-IP $remote_addr; 13 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 proxy_set_header X-Forwarded-Proto $scheme; 15 proxy_set_header Host $http_host; 16 proxy_set_header Upgrade $http_upgrade; 17 proxy_set_header Connection "Upgrade"; 18 proxy_pass_request_headers on; 19 add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive"; 20 } 21}

あとは、sudo nginx -tでNginxの設定に問題がないことを確認し、sudo systemctl start nginxでNginxを起動すれば、
Nginxの設定は完了です。

さらにUbuntu上でLet's EncryptによりSSLを設定する場合は、
↓こちらの記事の方法がとても参考になります(Nginxの設定から更新まで自動!)。
Ubuntu 20.04でLet’s Encryptを使用してNginxを保護する方法 | DigitalOcean

Node.jsでNext.jsとStrapiの環境を準備

Strapi公式のガイド: https://docs.strapi.io/dev-docs/integrations/next-js

Next.jsのインストール

1$ npx create-next-app@latest

でNext.jsをインストールします。

Strapiのインストール

ここでは、Next.jsをインストールした場所にstrapiをインストールしてみます。 StrapiをNext.jsと別の場所に置く場合などは、同じ場所にインストールしない方が良いでしょう。

1$ cd <Next.jsをインストールしたディレクトリ> 2$ yarn create strapi-app my-project --quickstart

でStrapiをインストールします。
このとき、利用するDBをSQLite、MySQL、MariaDB、PostgreSQLから選択できます。
SQLite以外を利用する場合は、別でMySQLなどインストール・きどうしておく必要があります。
ここではMySQLを使った方法をご紹介します。

MySQLのインストール

参考にさせていただいたサイト: Ubuntu 20.04にMySQLをインストールする方法 | DigitalOcean

インストール

1$ sudo apt update 2$ sudo apt install mysql-server

設定

パスワード
1$ sudo mysql_secure_installation

ここでいくつか質問されるので、
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:では 2、
Re-enter new password:では新たなパスワード、
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : で Y
として、パスワードを設定します。

ユーザ追加と権限の付与
1$ mysql -u root -p
1CREATE USER 'ユーザ名'@'localhost' IDENTIFIED BY 'ユーザ名'; 2GRANT ALL PRIVILEGES ON * . * TO 'ユーザ名'@'localhost'; 3FLUSH PRIVILEGES;
Strapi用DBの作成
1exit
1mysql -u ユーザ名 -p
1CREATE DATABASE strapi;

これでMySQLの準備は完了。
Strapiのディレクトリに既にある.env、なければ新規に.envという名前のファイルを作り、以下のように記述
.env

12DATABASE_CLIENT=mysql2 3DATABASE_HOST=127.0.0.1 4DATABASE_PORT=3306 5DATABASE_NAME=strapi 6DATABASE_USERNAME=ユーザ名 7DATABASE_PASSWORD=パスワード 8DATABASE_SSL=false

続いて、./config/database.jsというファイルを開き、以下のように設定します。

1module.exports = ({ env }) => ({ 2 connection: { 3 client: 'mysql', 4 connection: { 5 host: env('DATABASE_HOST', '127.0.0.1'), 6 port: env.int('DATABASE_PORT', 3306), 7 database: env('DATABASE_NAME', 'strapi'), 8 user: env('DATABASE_USERNAME', 'strapi'), 9 password: env('DATABASE_PASSWORD', 'strapi'), 10 ssl: { 11 rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false), // For self-signed certificates 12 }, 13 }, 14 debug: false, 15 }, 16});

Strapiのディレクトリで以下コマンドを実行すると、Strapiが立ち上がり、表示されたURLにアクセスすると、ユーザ登録画面が表示されます。

1yarn develop

Next.jsとStrapiでデータを連携する

SSGでNext.jsからStrapiのAPIを呼び出す

※Strapiでrestaurantというコンテンツタイプを作った場合を例にしています(フィールドはtitleとslugを設定)。

SSGでNext.jsからAPIを呼び出す場合、pages/ のファイルで、getStaticProps()を使うことで、 ページをジェネレートする前にAPIを呼び出して、静的にHTMLを出力できます。

1import axios from 'axios' 2 3function Page ({ posts, pagination, error } { 4 return ( 5 <section> 6 <h1>ページサンプル</h1> 7 <ul> 8 posts.map(post => ( 9 <li key={post.id}>{post?.attribute?.title}</li> 10 )) 11 </ul> 12 </section> 13 ) 14} 15 16export async function getStaticProps () { 17 try { 18 const res = await axios.get('http://localhost:1337/api/restaurants'); 19 20 return { 21 props: { 22 posts: res?.data, 23 pagination: { 24 ...res?.meta?.pagination 25 } 26 } 27 } 28 } catch (error) { 29 return { error } 30 } 31} 32 33export default Page

ダイナミックルーティングでSSGする

pages/restaurants/[slug]/index.tsx のようにダイナミックルーティングでslugごとのページを生成したい場合、
getStaticPathsを使います。

1import axios from 'axios'; 2 3function Page ({ post } { 4 return ( 5 <section> 6 <h1>{post?.attribute?.title}</h1> 78 </section> 9 ) 10} 11 12export async function getStaticPaths () { 13 let paths: (string | { 14 params: ParsedUrlQuery; 15 locale?: string | undefined; 16 })[] = [] 17 const res = await axios.get(`http://localhost:1337/api/restaurants?pagination[pageSize]=10000&populate=slug`) 18 if (res?.data?.length > 0) { 19 paths = res?.data?.map(post => ({ 20 params: { 21 slug: post?.attributes?.slug ?? null 22 } 23 })) 24 } 25 return { paths, fallback: false } 26} 27 28export async function getStaticProps ({ params }) { 29 const res = await axios.get(`http://localhost:1337/api/restaurants?filters\[slug\][$eq]=${ params?.slug }`); 30 31 return { 32 props: { 33 post: res?.data?.length > 0 ? res?.data[0] : undefined, 34 } 35 } 36} 37 38export default Page

対応してみた感想

WordPressに比べると、事前の準備も多く必要で、慣れるまでは大変かもしれません。
SSGの場合、記事が多ければ多いほどビルドまでに時間がかかる問題もあります。
ただ、基本的には1つの言語でバックエンドからフロントエンドまで調整することが可能で、
SSGが故にクライアント側の表示は高速で、ビルドするとき以外はサーバの負担も軽くすみます。

Strapiはコンテンツも自由に設定でき、実際に拡張性は高いと感じました。
また、無料で試せるので、ヘッドレスCMSの練習としてもいいと思いました。

2023.8.28 追記

数百ページを超えるようなサイトでは、記事を更新するたびに全ページをbuildするSSGは向きません。
その場合、Next.jsではISR(Incremental Static Regenerate)という仕組みが用意されていて、設定を工夫することで大量のページを含むサイトにも対応できるので、そちらの利用のご検討をおすすめします。

Author Profile

著者近影

NINOMIYA

Webデザイナー兼コーダー出身のフロントエンド開発者です。 UXデザインやチーム開発の効率化など、勉強中です。

SHARE

合わせて読みたい