🕌
ステージングにIP制限を実装 (Next.js & Vercel)
はじめに
- 特定の IP からのアクセスを ブロック/許可する簡易方法を紹介します。
- ステージングのURLなどで、特定の IP からのアクセスを許可する場合などに利用できます。
- 実装は
middleware.ts
と環境変数.env.local
の設定のみで完了します。 - 作業したコードは以下になります。
結論
-
middleware.ts
と.env.local
の設定のみで実装できます。 - 環境変数の
IP_WHITE_LIST
からホワイトリストに追加されたIPを取得します。 - 環境変数の
ACCESS_RESTRICTION_FQDN_LIST
からアクセス制限対象のFQDNを取得します。 -
request.ip
からアクセス元のIPを取得します。 -
request.nextUrl.host
からアクセス先のFQDNを取得します。 - アクセス元のIPがホワイトリストに入っていれば、ステージングのURLにアクセスできます。
middleware.ts
// middleware.ts
import { NextResponse, type NextRequest } from "next/server";
// ホワイトリストに登録されたIPリストを取得します。
const ipWhiteList = new Set(
process.env.IP_WHITE_LIST?.split(",").map((item: string) => {
return item.trim();
})
);
// アクセス制限対象のFQDNを取得します。
const accessRestrictionFqdnList = new Set(
process.env.ACCESS_RESTRICTION_FQDN_LIST?.split(",").map((item: string) => {
return item.trim();
})
);
export function middleware(request: NextRequest) {
if (process.env.NODE_ENV === "production") {
if (
!ipWhiteList.has(request.ip as string) &&
accessRestrictionFqdnList.has(request.nextUrl.host)
) {
console.info(
`ホワイトリストに追加されていないIPアドレスからアクセスされたため、アクセスを拒否しました。[request.ip = ${request.ip}, request.nextUrl.host = ${request.nextUrl.host}]`
);
return new NextResponse(null, { status: 401 });
} else {
console.info(
`ホワイトリストに追加されているIPアドレスからアクセスされました。[request.ip = ${request.ip}, request.nextUrl.host = ${request.nextUrl.host}]`
);
}
}
}
実装
実際に、Next.js, Vercel で実装してみます。
Next.jsプロジェクトの新規作成
作業するプロジェクトを新規に作成していきます。
長いので、折りたたんでおきます。
新規プロジェクト作成と初期環境構築の手順詳細
$ pnpm create next-app@latest nextjs-ip-block-sample --typescript --eslint --import-alias "@/*" --src-dir --use-pnpm --tailwind --app
$ cd nextjs-ip-block-sample
以下の通り不要な設定を削除し、プロジェクトの初期環境を構築します。
$ mkdir src/styles
$ mv src/app/globals.css src/styles/globals.css
src/styles/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
src/app/page.tsx
export default function Home() {
return (
<main className="text-lg">
テストページ
</main>
)
}
src/app/layout.tsx
import '@/styles/globals.css'
export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja">
<body className="">{children}</body>
</html>
);
}
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
plugins: [],
};
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
+ "baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
コミットします。
$ pnpm build
$ git add .
$ git commit -m "新規にプロジェクトを作成し, 作業環境を構築"
環境変数にアクセス制限をかけるステージング環境のFQDNを追加
環境変数にアクセス制限をかけるステージング環境のFQDNを追加します。https://www.google.com
の場合、 FGDNはwww.google.com
になります。
$ touch .env.local
.env.local
環境変数にステージング環境へのアクセスを許可するIPを追加
環境変数にステージング環境へのアクセスを許可するIPを追加します。
.env.local
STG_DOMAIN_LIST=stg.vercelstudy1akdl.com
+IP_WHITE_LIST=XXX.XX.XXX.XXX, YYYY.YY.YYY.YYY
↑ 実際は自身のIPを追加してください。自分のIPは以下から確認できます。
特定のIPからのみステージング環境へのアクセスを許可
- 環境変数の
IP_WHITE_LIST
からホワイトリストに追加されたIPを取得します。 - 環境変数の
ACCESS_RESTRICTION_FQDN_LIST
からアクセス制限対象のFQDNを取得します。 -
request.ip
からアクセス元のIPを取得します。 -
request.nextUrl.host
からアクセス先のFQDNを取得します。
$ touch src/middleware.ts
middleware.ts
// middleware.ts
import { NextResponse, type NextRequest } from "next/server";
// ホワイトリストに登録されたIPリストを取得します。
const ipWhiteList = new Set(
process.env.IP_WHITE_LIST?.split(",").map((item: string) => {
return item.trim();
})
);
// アクセス制限対象のFQDNを取得します。
const accessRestrictionFqdnList = new Set(
process.env.ACCESS_RESTRICTION_FQDN_LIST?.split(",").map((item: string) => {
return item.trim();
})
);
export function middleware(request: NextRequest) {
if (process.env.NODE_ENV === "production") {
if (
!ipWhiteList.has(request.ip as string) &&
accessRestrictionFqdnList.has(request.nextUrl.host)
) {
console.info(
`ホワイトリストに追加されていないIPアドレスからアクセスされたため、アクセスを拒否しました。[request.ip = ${request.ip}, request.nextUrl.host = ${request.nextUrl.host}]`
);
return new NextResponse(null, { status: 401 });
} else {
console.info(
`ホワイトリストに追加されているIPアドレスからアクセスされました。[request.ip = ${request.ip}, request.nextUrl.host = ${request.nextUrl.host}]`
);
}
}
}
コミットします。
$ pnpm build
$ git add .
$ git commit -m "middleware.tsを追加"
動作確認
動作確認するためには、Vercel などにデプロイする必要があります。ローカル環境では、pnpm dev
あるいは pnpm start
のいずれでも、request.ip
が undefined
になってしまうためです。
- GitHub にリポジトリを作成します。
- Vercel にデプロイします。
- 環境変数を追加します。
- ドメインを追加します。自前で取得したドメインを利用しています。
-
環境変数を修正したので、再度デプロイします。
-
ブラウザで確認します。
ホワイトリストに追加されているIPからのアクセスは許可されます。
ホワイトリストに追加されていないIPからのアクセスは拒否されます。
Vercel のログを確認します。
ホワイトリストに追加されているIPからのアクセスは許可されます。
ホワイトリストに追加されていないIPからのアクセスは拒否されます。
まとめ
- 特定の IP からのアクセスを ブロック/許可する簡易方法を紹介しました。
- ステージング環境などで、特定の IP からのアクセスを許可する場合などに利用できます。
- 実装は
middleware.ts
と環境変数の設定のみで完了します。 - 作業したコードは以下になります。
Discussion