T-CREATOR

Nginx を macOS で本番級に構築:launchd/ログローテーション/権限・署名のベストプラクティス

Nginx を macOS で本番級に構築:launchd/ログローテーション/権限・署名のベストプラクティス

macOS 上で Nginx を開発環境だけでなく、本番環境として運用したいと考えたことはありませんか?実は、macOS には Linux とは異なる独自のサービス管理や権限設計が存在し、それらを理解しないと思わぬトラブルに遭遇してしまいます。

本記事では、macOS で Nginx を本番級に運用するための launchd 設定、ログローテーション、権限管理、そしてコード署名まで、実践的なステップを丁寧に解説いたします。これらの知識があれば、macOS 上でも安心して Nginx を稼働させられるようになるでしょう。

macOS で Nginx を本番運用する際の課題

開発環境と本番環境の違い

開発環境では、nginx コマンドを手動で起動し、必要なときだけ使うという運用が一般的です。しかし本番環境では、システム再起動後も自動的に Nginx が起動し、ログが適切に管理され、セキュリティが保たれている必要があります。

Linux 環境であれば systemd や SysVinit といったサービス管理ツールが標準で用意されていますが、macOS では launchd という独自の仕組みを使います。また、ログローテーションも Linux の logrotate ではなく、macOS 標準の newsyslog を活用することになるのです。

以下の図は、開発環境と本番環境における Nginx 運用の違いを示しています。

mermaidflowchart LR
    dev["開発環境"] -->|手動起動| nginx_dev["Nginx"]
    nginx_dev -->|手動停止| dev

    prod["本番環境"] -->|自動起動| launchd["launchd"]
    launchd -->|プロセス管理| nginx_prod["Nginx"]
    nginx_prod -->|ログ出力| logs["ログファイル"]
    logs -->|自動ローテーション| newsyslog["newsyslog"]

本番環境では launchd がプロセスを管理し、ログは newsyslog が自動的にローテーションします。

macOS ならではの制約事項

macOS で Nginx を運用する際には、以下のような独自の制約に直面します。

#制約項目内容影響
1サービス管理systemd が使えず launchd を使う必要がある設定ファイル形式が XML(plist)になる
2ログローテーションlogrotate が標準搭載されていないnewsyslog を使った設定が必須
3権限管理BSD 系の権限体系Linux とは微妙に挙動が異なる
4ポート制限1024 番未満のポートは root 権限が必要80/443 番ポートのバインドに工夫が必要
5セキュリティポリシーGatekeeper による実行制限未署名バイナリは警告が表示される

特にポート 80 や 443 を使う場合、root 権限での実行が必要になりますが、セキュリティリスクを考慮すると可能な限り一般ユーザーで実行したいところです。この矛盾をどう解決するかが、macOS での Nginx 運用における最大のポイントとなるでしょう。

また、macOS Catalina 以降では Gatekeeper のセキュリティ強化により、インターネットからダウンロードしたバイナリや未署名のバイナリを実行しようとすると警告が表示されます。これらの制約を理解した上で、適切な設定を行う必要があるのです。

launchd による自動起動設定

launchd とは

launchd は macOS における標準的なサービス管理デーモンで、システム起動時やログイン時にプログラムを自動実行する役割を担っています。Linux の systemd に相当する存在ですが、設定方法や思想が大きく異なります。

launchd の主な特徴は以下の通りです。

  • XML 形式の plist ファイルで設定を記述
  • プロセスの監視と自動再起動機能
  • 起動タイミングを柔軟に制御(システム起動時、ログイン時、時刻指定など)
  • 環境変数や作業ディレクトリの設定が可能

以下の図は、launchd によるプロセス管理の流れを示しています。

mermaidflowchart TB
    boot["macOS 起動"] --> launchd["launchd 起動"]
    launchd --> plist["plist ファイル読み込み"]
    plist --> check{KeepAlive<br/>設定?}
    check -->|Yes| monitor["プロセス監視開始"]
    check -->|No| start["プロセス起動"]
    monitor --> nginx["Nginx 起動"]
    nginx --> crash{プロセス<br/>異常終了?}
    crash -->|Yes| restart["自動再起動"]
    restart --> nginx
    crash -->|No| running["正常稼働"]

launchd は plist ファイルの設定に従い、プロセスを起動・監視し、異常終了時には自動的に再起動を行います。

plist ファイルの作成

launchd で Nginx を管理するには、専用の plist ファイルを作成します。plist ファイルは ​/​Library​/​LaunchDaemons​/​(システム全体)または ~​/​Library​/​LaunchAgents​/​(ユーザーごと)に配置しますが、Nginx のようなサーバープロセスはシステム全体で動かすのが一般的です。

まず、plist ファイルのベースとなる構造を見ていきましょう。

xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- この中に設定を記述 -->
</dict>
</plist>

plist ファイルは XML 形式で、必ず上記のヘッダーと <dict> タグで囲む必要があります。

次に、Nginx 用の具体的な設定を追加します。

xml<key>Label</key>
<string>com.nginx.server</string>

<key>ProgramArguments</key>
<array>
    <string>/usr/local/bin/nginx</string>
    <string>-g</string>
    <string>daemon off;</string>
</array>

Label は一意な識別子で、ProgramArguments には実行するコマンドとオプションを配列形式で指定します。daemon off; オプションは重要で、これにより Nginx がフォアグラウンドで実行され、launchd による監視が可能になるのです。

続いて、自動起動と再起動の設定を追加しましょう。

xml<key>RunAtLoad</key>
<true/>

<key>KeepAlive</key>
<true/>

RunAtLoadtrue にすると、plist ファイルがロードされた時点で即座に起動します。KeepAlivetrue にすると、プロセスが異常終了した場合に自動的に再起動されます。

ログ出力の設定も重要です。

xml<key>StandardOutPath</key>
<string>/usr/local/var/log/nginx/launchd.out.log</string>

<key>StandardErrorPath</key>
<string>/usr/local/var/log/nginx/launchd.error.log</string>

これにより、Nginx の標準出力とエラー出力が指定したファイルに記録されます。トラブルシューティング時に非常に役立つでしょう。

最後に、作業ディレクトリと環境変数を設定します。

xml<key>WorkingDirectory</key>
<string>/usr/local/var/www</string>

<key>EnvironmentVariables</key>
<dict>
    <key>PATH</key>
    <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>

これで基本的な plist ファイルが完成しました。完全な設定ファイルは後述の「統合設定例」で紹介いたします。

起動スクリプトの設定

作成した plist ファイルを ​/​Library​/​LaunchDaemons​/​ に配置し、適切な権限を設定します。

bash# plistファイルを配置
sudo cp com.nginx.server.plist /Library/LaunchDaemons/

ファイルを配置したら、オーナーとパーミッションを設定します。

bash# オーナーをrootに設定
sudo chown root:wheel /Library/LaunchDaemons/com.nginx.server.plist

# パーミッションを644に設定(所有者のみ書き込み可能)
sudo chmod 644 /Library/LaunchDaemons/com.nginx.server.plist

セキュリティ上、plist ファイルは root 所有で、一般ユーザーが書き込めないようにする必要があります。

次に、必要なログディレクトリを作成します。

bash# ログディレクトリを作成
sudo mkdir -p /usr/local/var/log/nginx

# 権限を設定
sudo chown -R nginx:staff /usr/local/var/log/nginx
sudo chmod 755 /usr/local/var/log/nginx

ログディレクトリは Nginx ユーザーが書き込めるように権限を設定しましょう。

launchd にサービスを登録して起動します。

bash# plistファイルをロード(登録)
sudo launchctl load /Library/LaunchDaemons/com.nginx.server.plist

# サービスを起動
sudo launchctl start com.nginx.server

launchctl load コマンドで plist ファイルを launchd に登録し、start コマンドで実際にサービスを起動します。

自動起動の確認とトラブルシューティング

サービスが正常に起動しているか確認します。

bash# 起動中のサービス一覧を確認
sudo launchctl list | grep nginx

正常に起動していれば、以下のような出力が表示されます。

diff-    0    com.nginx.server

左から順に、PID(-は launchd が管理中)、終了ステータス(0 は正常)、ラベル名を示しています。

プロセスの詳細情報を確認しましょう。

bash# プロセス詳細を確認
ps aux | grep nginx

Nginx のマスタープロセスとワーカープロセスが表示されれば成功です。

yamlnginx    1234  0.0  0.1  2468  1024  ??  Ss    9:00AM   0:00.01 nginx: master process
nginx    1235  0.0  0.2  2468  2048  ??  S     9:00AM   0:00.02 nginx: worker process

トラブルが発生した場合は、ログファイルを確認します。

bash# launchdのエラーログを確認
cat /usr/local/var/log/nginx/launchd.error.log

# macOSのシステムログを確認(Nginxに関する直近のログ)
log show --predicate 'processImagePath contains "nginx"' --last 1h

よくあるエラーとして、以下のようなケースがあります。

#エラー内容原因解決方法
1nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)ポート 80 へのバインド権限がないroot 権限で起動するか、ポートフォワーディングを使用
2Path had bad ownership​/​permissionsplist ファイルの権限が不適切sudo chown root:wheelsudo chmod 644 を実行
3Service is disabledサービスが無効化されているsudo launchctl enable system​/​com.nginx.server を実行
4Could not find specified serviceLabel が間違っているplist ファイルの Label 名を確認

サービスを停止・削除する場合は、以下のコマンドを使用します。

bash# サービスを停止
sudo launchctl stop com.nginx.server

# plistをアンロード(登録解除)
sudo launchctl unload /Library/LaunchDaemons/com.nginx.server.plist

設定を変更した場合は、一度アンロードしてから再度ロードする必要があります。

ログローテーション戦略

macOS におけるログ管理の課題

Nginx を長期間運用すると、アクセスログやエラーログがどんどん肥大化していきます。特にアクセス数の多いサーバーでは、1 日で数百 MB から数 GB ものログが蓄積されることも珍しくありません。

ログファイルが大きくなりすぎると、以下のような問題が発生します。

  • ディスク容量の圧迫: ログファイルがディスクを占有し、他の処理に影響
  • 検索・分析の困難: 巨大なログファイルは grep や解析ツールでの処理が遅い
  • バックアップの肥大化: ログを含めたバックアップサイズが膨大に
  • パフォーマンス低下: ログ書き込みの I/O 負荷が増大

Linux 環境では logrotate という専用ツールがありますが、macOS には標準搭載されていません。代わりに macOS では newsyslog というツールが古くから使われており、こちらを活用することになります。

以下の図は、ログローテーションの仕組みを示しています。

mermaidflowchart LR
    nginx["Nginx"] -->|書き込み| current["access.log"]
    newsyslog["newsyslog"] -->|定期実行| check{サイズ/日時<br/>条件達成?}
    check -->|Yes| rotate["ログローテーション"]
    check -->|No| wait["待機"]
    rotate --> rename["access.log<br/>→ access.log.0"]
    rename --> compress["access.log.0<br/>→ access.log.0.gz"]
    compress --> new["新規 access.log<br/>作成"]
    new --> signal["Nginx へ<br/>SIGHUP 送信"]
    signal --> reopen["ログファイル<br/>再オープン"]

newsyslog は定期的にログファイルをチェックし、条件を満たしたらローテーションを実行します。その後、Nginx にシグナルを送ってログファイルを再オープンさせるのです。

newsyslog を使った設定

newsyslog は macOS に標準搭載されており、​/​etc​/​newsyslog.conf または ​/​etc​/​newsyslog.d​/​ ディレクトリ内の設定ファイルで動作を制御します。独自の設定は ​/​etc​/​newsyslog.d​/​ に配置するのがベストプラクティスです。

まず、newsyslog の設定ファイル形式を理解しましょう。

css# ログファイル [オーナー:グループ] モード 数 サイズ 間隔 フラグ [PIDファイル] [シグナル]

各フィールドの意味は以下の通りです。

#フィールド説明
1ログファイルパスローテーション対象のログファイル​/​usr​/​local​/​var​/​log​/​nginx​/​access.log
2オーナー:グループローテーション後の所有者nginx:staff
3モードパーミッション(8 進数)644
4保持する世代数7
5サイズローテーションするサイズ(KB 単位、*は無制限)102400(100MB)
6間隔時間ベースのローテーション@T00(毎日 0 時)、$D0(日次)
7フラグ動作オプションGZN(圧縮、空でも作成、バイナリ)
8PID ファイルシグナル送信先の PID ファイル​/​usr​/​local​/​var​/​run​/​nginx.pid
9シグナル送信するシグナルSIGHUP

基本的な設定例を見てみましょう。

swift# アクセスログを100MBまたは日次でローテーション
/usr/local/var/log/nginx/access.log  nginx:staff  644  7  102400  @T00  GZN  /usr/local/var/run/nginx.pid  SIGHUP

この設定では、access.log が 100MB に達するか、毎日 0 時になったらローテーションが実行されます。

より詳細な設定オプションについて説明します。

bash# フラグの詳細
# G: gzip圧縮を行う
# Z: bzip2圧縮を行う
# N: 空のログファイルでも新規作成する
# B: バイナリファイルとして扱う
# C: ログファイルが存在しなくても作成する

フラグは組み合わせて使用でき、GZN なら「gzip 圧縮、空でも作成、バイナリ扱い」となります。

ログローテーション設定ファイルの作成

Nginx 専用の newsyslog 設定ファイルを作成しましょう。

bash# 設定ファイルを作成
sudo vi /etc/newsyslog.d/nginx.conf

以下の内容を記述します。

swift# Nginx アクセスログ(サイズベース + 日次ローテーション)
/usr/local/var/log/nginx/access.log  nginx:staff  644  30  102400  @T00  GZN  /usr/local/var/run/nginx.pid  SIGHUP

アクセスログは 100MB または毎日 0 時にローテーションし、30 世代保持、gzip 圧縮を行う設定です。

次に、エラーログの設定を追加します。

swift# Nginx エラーログ(日次ローテーションサイズ制限なし)
/usr/local/var/log/nginx/error.log  nginx:staff  644  14  *  $D0  GZN  /usr/local/var/run/nginx.pid  SIGHUP

エラーログはサイズに関係なく日次でローテーションし、14 世代(2 週間分)を保持します。

launchd のログも合わせて管理しましょう。

perl# launchd 標準出力ログ
/usr/local/var/log/nginx/launchd.out.log  nginx:staff  644  7  10240  $D0  GZ

# launchd エラーログ
/usr/local/var/log/nginx/launchd.error.log  nginx:staff  644  7  10240  $D0  GZ

launchd のログは Nginx のプロセスとは無関係なので、PID ファイルやシグナルの指定は不要です。

設定ファイルの構文チェックを行います。

bash# 構文チェック(実際にはローテーションしない)
sudo newsyslog -nvv

-n オプションは dry-run(実際には実行しない)、-vv は詳細出力を意味します。エラーがなければ、どのログがローテーション対象かが表示されるでしょう。

動作確認とテスト

実際にログローテーションを手動で実行してテストします。

bash# 強制的にローテーションを実行
sudo newsyslog -v

正常に動作すれば、以下のような処理が行われます。

lua/usr/local/var/log/nginx/access.log <nginx:staff>: size (Kb): 98765 [100MB] --> trimming log

ログファイルの状態を確認しましょう。

bash# ローテーション後のログファイル一覧
ls -lh /usr/local/var/log/nginx/

以下のようなファイルが生成されていれば成功です。

c-rw-r--r--  1 nginx  staff     0B  1  1 00:00 access.log
-rw-r--r--  1 nginx  staff   45M  1  1 00:00 access.log.0.gz
-rw-r--r--  1 nginx  staff     0B  1  1 00:00 error.log
-rw-r--r--  1 nginx  staff   1.2M  1  1 00:00 error.log.0.gz

新しい access.log が作成され、古いログは .0.gz という名前で圧縮保存されています。

Nginx がログファイルを正しく再オープンしているか確認します。

bash# Nginxのログファイルディスクリプタを確認
sudo lsof -p $(cat /usr/local/var/run/nginx.pid) | grep log

新しい access.logerror.log がオープンされていれば、SIGHUP シグナルが正しく処理されています。

newsyslog は cron によって自動実行されますが、実行タイミングを確認しておきましょう。

bash# newsyslogのcron設定を確認
cat /etc/periodic/daily/999.local

macOS では ​/​etc​/​periodic​/​daily​/​ 配下のスクリプトが毎日実行されます。newsyslog は通常 ​/​etc​/​periodic​/​daily​/​500.daily として登録されており、毎日深夜 3 時頃に実行されるのです。

トラブルシューティングのポイントをまとめます。

#問題原因解決方法
1ログがローテーションされない設定ファイルの構文エラーsudo newsyslog -nvv で確認
2権限エラーが発生オーナーやモードが不適切設定ファイルの 2・3 番目のフィールドを確認
3Nginx が新しいログに書き込まないSIGHUP が送信されていないPID ファイルパスとシグナル設定を確認
4圧縮ファイルが作成されないフラグに G または Z がないフラグフィールドに G を追加

権限設定のベストプラクティス

実行ユーザーの選定

セキュリティの観点から、Nginx を root ユーザーで実行し続けるのは望ましくありません。万が一 Nginx に脆弱性があった場合、攻撃者にシステム全体を掌握されるリスクがあるためです。

理想的な構成は以下の通りです。

  • マスタープロセス: root ユーザーで起動(ポート 80/443 へのバインドのため)
  • ワーカープロセス: 専用の nginx ユーザーで実行(実際のリクエスト処理)

まず、Nginx 専用のユーザーを作成しましょう。

bash# システムユーザーIDを確認(既存の最大値を調べる)
dscl . -list /Users UniqueID | sort -k2 -n | tail -1

macOS では、ユーザー ID 200〜400 がシステムユーザー用に予約されています。

nginx ユーザーを作成します。

bash# nginxグループを作成(グループID: 250)
sudo dscl . -create /Groups/nginx
sudo dscl . -create /Groups/nginx PrimaryGroupID 250

グループを作成したら、ユーザーを作成します。

bash# nginxユーザーを作成(ユーザーID: 250)
sudo dscl . -create /Users/nginx
sudo dscl . -create /Users/nginx UniqueID 250
sudo dscl . -create /Users/nginx PrimaryGroupID 250
sudo dscl . -create /Users/nginx UserShell /usr/bin/false
sudo dscl . -create /Users/nginx NFSHomeDirectory /var/empty
sudo dscl . -create /Users/nginx RealName "Nginx User"

UserShell​/​usr​/​bin​/​false に設定することで、このユーザーではログインできなくなります。セキュリティ上重要な設定です。

作成したユーザーを確認しましょう。

bash# ユーザー情報を確認
id nginx

正常に作成されていれば、以下のような出力が表示されます。

scssuid=250(nginx) gid=250(nginx) groups=250(nginx)

次に、Nginx の設定ファイルでワーカープロセスの実行ユーザーを指定します。

nginx# /usr/local/etc/nginx/nginx.conf の先頭に追加
user nginx staff;

user ディレクティブで、ワーカープロセスを nginx ユーザー、staff グループで実行するよう指定します。macOS では staff グループがデフォルトのユーザーグループとして使われることが多いためです。

ディレクトリ権限の設計

Nginx が正常に動作するには、各種ディレクトリに適切な権限を設定する必要があります。セキュリティと機能性のバランスを考慮した権限設計を行いましょう。

以下は、Nginx で使用する主要なディレクトリと推奨権限の一覧です。

#ディレクトリ用途推奨権限オーナー理由
1​/​usr​/​local​/​etc​/​nginx​/​設定ファイル755root:wheel設定改ざん防止
2​/​usr​/​local​/​var​/​log​/​nginx​/​ログファイル755nginx:staffNginx が書き込み可能
3​/​usr​/​local​/​var​/​run​/​PID ファイル755root:wheelランタイム情報
4​/​usr​/​local​/​var​/​www​/​ドキュメントルート755nginx:staff静的ファイル配信
5​/​usr​/​local​/​var​/​cache​/​nginx​/​キャッシュ700nginx:staff他ユーザーアクセス不要

設定ファイルディレクトリの権限を設定します。

bash# 設定ディレクトリの権限設定
sudo chown -R root:wheel /usr/local/etc/nginx/
sudo chmod 755 /usr/local/etc/nginx/
sudo chmod 644 /usr/local/etc/nginx/*.conf

設定ファイルは root のみが編集可能にし、他のユーザーは読み取り専用とします。

ログディレクトリの権限を設定します。

bash# ログディレクトリの権限設定
sudo chown -R nginx:staff /usr/local/var/log/nginx/
sudo chmod 755 /usr/local/var/log/nginx/
sudo chmod 644 /usr/local/var/log/nginx/*.log

nginx ユーザーが書き込めるようにしつつ、他のユーザーは読み取り専用とします。

ドキュメントルートの権限を設定しましょう。

bash# ドキュメントルートの権限設定
sudo chown -R nginx:staff /usr/local/var/www/
sudo chmod 755 /usr/local/var/www/
sudo find /usr/local/var/www/ -type f -exec chmod 644 {} \;
sudo find /usr/local/var/www/ -type d -exec chmod 755 {} \;

ディレクトリは 755(実行権限が必要)、ファイルは 644(読み取り専用で十分)とします。

キャッシュディレクトリはより厳密な権限にします。

bash# キャッシュディレクトリの権限設定
sudo mkdir -p /usr/local/var/cache/nginx/
sudo chown -R nginx:staff /usr/local/var/cache/nginx/
sudo chmod 700 /usr/local/var/cache/nginx/

キャッシュは nginx ユーザー以外がアクセスする必要がないため、700(所有者のみアクセス可)とします。

ポート 80/443 へのバインド対策

macOS では、1024 番未満のポート(いわゆる特権ポート)にバインドするには root 権限が必要です。しかし、root ユーザーで Nginx を実行し続けるのはセキュリティリスクが高いため、工夫が必要となります。

主な対策方法は以下の 3 つです。

mermaidflowchart TB
    problem["ポート 80/443 へのバインド問題"] --> method1["方法1: マスタープロセスのみroot実行"]
    problem --> method2["方法2: pfctl によるポートフォワーディング"]
    problem --> method3["方法3: リバースプロキシの利用"]

    method1 --> m1_result["ワーカープロセスは nginx ユーザー"]
    method2 --> m2_result["nginx ユーザーで 8080 を Listen<br/>80 → 8080 へ転送"]
    method3 --> m3_result["Caddy や Apache を前段に配置"]

各方法にはメリット・デメリットがありますので、環境に応じて選択しましょう。

方法 1: マスタープロセスのみ root 実行

最も一般的な方法で、Nginx の標準的な動作です。

nginx# nginx.conf
user nginx staff;

events {
    worker_connections 1024;
}

http {
    # 80番ポートでリッスン
    server {
        listen 80;
        server_name localhost;
        root /usr/local/var/www;
    }
}

この設定で root ユーザーが Nginx を起動すると、マスタープロセスのみが root で実行され、実際のリクエスト処理を行うワーカープロセスは nginx ユーザーで実行されます。

起動方法は以下の通りです。

bash# rootユーザーで起動
sudo /usr/local/bin/nginx

launchd で自動起動する場合は、plist ファイルで UserName を指定しないことで root として起動されます。

方法 2: pfctl によるポートフォワーディング

nginx ユーザーで 8080 番ポートを Listen し、pfctl(Packet Filter)でポート 80 からの通信を 8080 へ転送する方法です。

まず、Nginx の設定を変更します。

nginx# nginx.conf(8080番ポートでリッスン)
server {
    listen 8080;
    server_name localhost;
    root /usr/local/var/www;
}

次に、pfctl のルール設定ファイルを作成します。

bash# pfctl用のルールファイルを作成
sudo vi /etc/pf.anchors/nginx

以下の内容を記述します。

python# ポート80 → 8080へリダイレクト
rdr pass on lo0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
rdr pass on en0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080

lo0 はループバックインターフェース、en0 はプライマリネットワークインターフェースです。

メインの pf.conf にアンカーを追加します。

bash# pf.confを編集
sudo vi /etc/pf.conf

以下の行を追加します。

csharp# rdrアンカーの読み込み
rdr-anchor "nginx"
load anchor "nginx" from "/etc/pf.anchors/nginx"

pfctl を有効化して、設定を反映させます。

bash# pfctlを有効化
sudo pfctl -e

# 設定を読み込み
sudo pfctl -f /etc/pf.conf

この方法なら、nginx ユーザーでプロセス全体を実行できるため、セキュリティリスクが低減されます。

方法 3: リバースプロキシの利用

Caddy や Apache など、特権ポートに対応した別のサーバーをフロントに配置し、Nginx をバックエンドとして利用する方法もあります。ただし、構成が複雑になるため、特別な理由がない限り方法 1 または方法 2 を推奨します。

セキュリティ強化設定

権限設定に加えて、Nginx 自体のセキュリティ設定も重要です。

まず、サーバートークンの非表示化を行います。

nginx# nginx.conf
http {
    # バージョン情報を隠す
    server_tokens off;
}

これにより、エラーページに表示される Nginx のバージョン情報が非表示になります。

不要な HTTP メソッドを制限しましょう。

nginx# 許可するHTTPメソッドを制限
location / {
    limit_except GET HEAD POST {
        deny all;
    }
}

GET、HEAD、POST 以外のメソッドをすべて拒否します。

ファイルアップロードサイズの制限も重要です。

nginxhttp {
    # アップロードサイズを制限(10MB)
    client_max_body_size 10M;

    # ボディバッファサイズ
    client_body_buffer_size 128k;
}

これにより、巨大なリクエストによる DoS 攻撃を防ぎます。

タイムアウト設定を適切に行いましょう。

nginxhttp {
    # クライアント接続タイムアウト
    client_body_timeout 12;
    client_header_timeout 12;

    # レスポンス送信タイムアウト
    send_timeout 10;

    # キープアライブタイムアウト
    keepalive_timeout 15;
}

短めのタイムアウトを設定することで、リソースの無駄遣いを防げます。

コード署名と公証

macOS のセキュリティポリシー

macOS Catalina(10.15)以降、Apple はセキュリティを大幅に強化し、Gatekeeper という仕組みで実行可能ファイルを厳格に管理しています。インターネットからダウンロードしたファイルや、未署名のバイナリを実行しようとすると、以下のような警告が表示されるのです。

「"nginx" は開発元が未確認のため開けません。」

この警告は、ユーザーを悪意あるソフトウェアから守るための仕組みですが、正規の用途であっても表示されてしまいます。特に企業内で Nginx を配布する場合、この警告は混乱を招くでしょう。

macOS のセキュリティレイヤーは以下のように階層化されています。

mermaidflowchart TB
    download["バイナリのダウンロード/ビルド"] --> quarantine["Quarantine 属性の付与"]
    quarantine --> first_run["初回実行時"]
    first_run --> gatekeeper["Gatekeeper チェック"]
    gatekeeper --> signature{コード署名<br/>あり?}
    signature -->|No| warning1["警告表示:<br/>開発元未確認"]
    signature -->|Yes| notarize{公証<br/>あり?}
    notarize -->|No| warning2["警告表示:<br/>公証されていません"]
    notarize -->|Yes| xprotect["XProtect スキャン"]
    xprotect --> run["実行許可"]

Gatekeeper はコード署名と公証の 2 段階でチェックを行い、両方をパスして初めて警告なしで実行できます。

Quarantine(検疫)属性について理解しておきましょう。

bash# ダウンロードしたファイルのQuarantine属性を確認
xattr /usr/local/bin/nginx

以下のような出力があれば、Quarantine 属性が付いています。

com.apple.quarantine

この属性があると、初回実行時に Gatekeeper のチェックが入ります。

Gatekeeper 対応

Gatekeeper の警告を回避する方法は、主に以下の 3 つです。

#方法メリットデメリット推奨度
1Quarantine 属性の削除即座に実行可能一時的な対処、配布に不向き★☆☆
2コード署名の適用開発元が明示されるApple Developer 登録が必要★★☆
3公証(Notarization)最も安全、警告なし手続きが複雑、有料★★★

方法 1: Quarantine 属性の削除

最も簡単な方法ですが、セキュリティリスクがあるため推奨されません。

bash# Quarantine属性を削除
sudo xattr -d com.apple.quarantine /usr/local/bin/nginx

この方法は、自分でビルドしたバイナリや、信頼できるソースから入手したファイルにのみ使用すべきです。

削除されたか確認します。

bash# 属性が削除されたか確認(何も表示されなければ成功)
xattr /usr/local/bin/nginx

方法 2: システム環境設定での許可

GUI から個別に実行を許可することもできます。

bash# システム環境設定のセキュリティ設定を開く
open "x-apple.systempreferences:com.apple.preference.security?General"

警告ダイアログが表示された後、「システム環境設定」→「セキュリティとプライバシー」→「一般」タブに「このまま開く」ボタンが表示されるので、これをクリックします。

ただし、この方法も一時的な対処であり、他のユーザーに配布する場合には適していません。

方法 3: spctl コマンドによる確認

システムポリシーコントロール(spctl)で Gatekeeper の判定を確認できます。

bash# Gatekeeperの判定を確認
spctl --assess --type execute /usr/local/bin/nginx

署名がない場合、以下のようなエラーが表示されます。

ini/usr/local/bin/nginx: rejected
source=no usable signature

署名付きバイナリの検証

コード署名を適用するには、Apple Developer Program への登録(年間 11,800 円)が必要です。登録後、以下の手順で署名を行います。

まず、証明書をキーチェーンにインストールします。

bash# 利用可能な署名用証明書を確認
security find-identity -v -p codesigning

以下のような証明書が表示されれば使用可能です。

arduino1) ABC123DEF456 "Developer ID Application: Your Name (TEAM123456)"

codesign コマンドで署名を適用します。

bash# バイナリに署名
codesign --sign "Developer ID Application: Your Name (TEAM123456)" \
         --force \
         --timestamp \
         --options runtime \
         /usr/local/bin/nginx

各オプションの意味は以下の通りです。

  • --sign: 使用する証明書
  • --force: 既存の署名を上書き
  • --timestamp: タイムスタンプサーバーを使用(署名の有効期限延長)
  • --options runtime: Hardened Runtime を有効化(macOS 10.14 以降で必須)

署名が正しく適用されたか確認しましょう。

bash# 署名を検証
codesign --verify --deep --strict --verbose=2 /usr/local/bin/nginx

成功すれば以下のように表示されます。

swift/usr/local/bin/nginx: valid on disk
/usr/local/bin/nginx: satisfies its Designated Requirement

署名の詳細情報を確認します。

bash# 署名情報を表示
codesign --display --verbose=4 /usr/local/bin/nginx

以下のような情報が表示されます。

iniExecutable=/usr/local/bin/nginx
Identifier=nginx
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=12345 flags=0x10000(runtime) hashes=123+5 location=embedded
Signature size=4567
Authority=Developer ID Application: Your Name (TEAM123456)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=20251112:00:00

これで、開発元が明示された署名付きバイナリが完成しました。

企業内配布時の注意点

企業内で Nginx を複数の macOS 端末に配布する場合、以下の点に注意が必要です。

公証(Notarization)の実施

署名だけでは、初回実行時に「開発元は確認済みですが、Apple によるマルウェアスキャンが実施されていません」という警告が表示されることがあります。これを回避するには、Apple の公証サービスにバイナリを提出する必要があります。

公証の手順は以下の通りです。

bash# バイナリをZIPで圧縮
ditto -c -k --keepParent /usr/local/bin/nginx nginx.zip

公証サービスに提出します。

bash# 公証サービスに提出
xcrun notarytool submit nginx.zip \
    --apple-id "your-email@example.com" \
    --password "app-specific-password" \
    --team-id "TEAM123456" \
    --wait

--wait オプションを付けると、公証が完了するまで待機します(通常数分)。

公証が完了したら、スタンプ(チケット)をバイナリに添付します。

bash# 公証チケットを添付
xcrun stapler staple /usr/local/bin/nginx

スタンプが正しく添付されたか確認しましょう。

bash# スタンプを検証
xcrun stapler validate /usr/local/bin/nginx

成功すれば以下のように表示されます。

rubyProcessing: /usr/local/bin/nginx
The validate action worked!

MDM(Mobile Device Management)による配布

大規模な企業環境では、Jamf Pro や Kandji などの MDM ソリューションを使って Nginx を配布することになるでしょう。MDM を使う場合、以下の設定が重要です。

xml<!-- MDM プロファイルの例 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>PayloadType</key>
            <string>com.apple.system.approved-apps</string>
            <key>TeamIdentifier</key>
            <string>TEAM123456</string>
        </dict>
    </array>
</dict>
</plist>

MDM プロファイルで Team Identifier を指定することで、該当する開発者の署名付きアプリを自動的に許可できます。

バージョン管理とアップデート

署名付きバイナリを配布する際は、バージョン管理も重要です。

bash# バイナリのバージョン情報を確認
/usr/local/bin/nginx -v

バージョン情報をログに記録しておくと、トラブルシューティング時に役立ちます。

bash# バージョン情報をログに記録
/usr/local/bin/nginx -v 2>&1 | tee /usr/local/var/log/nginx/version.log

アップデート時は、必ず新しいバイナリに署名し直してから配布しましょう。古い署名のままでは、整合性チェックでエラーが発生する可能性があります。

統合設定例

完全な設定ファイル一式

ここまで説明してきた設定を統合した、本番環境で使える完全な設定ファイル一式を紹介します。

launchd plist ファイル​/​Library​/​LaunchDaemons​/​com.nginx.server.plist

xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- サービスの一意な識別子 -->
    <key>Label</key>
    <string>com.nginx.server</string>

    <!-- 実行するプログラムと引数 -->
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/nginx</string>
        <string>-g</string>
        <string>daemon off;</string>
    </array>

    <!-- システム起動時に自動実行 -->
    <key>RunAtLoad</key>
    <true/>

    <!-- プロセス監視と自動再起動 -->
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
    </dict>

    <!-- 標準出力ログ -->
    <key>StandardOutPath</key>
    <string>/usr/local/var/log/nginx/launchd.out.log</string>

    <!-- エラー出力ログ -->
    <key>StandardErrorPath</key>
    <string>/usr/local/var/log/nginx/launchd.error.log</string>

    <!-- 作業ディレクトリ -->
    <key>WorkingDirectory</key>
    <string>/usr/local/var/www</string>

    <!-- 環境変数 -->
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>

    <!-- プロセス制限 -->
    <key>SoftResourceLimits</key>
    <dict>
        <key>NumberOfFiles</key>
        <integer>4096</integer>
    </dict>

    <key>HardResourceLimits</key>
    <dict>
        <key>NumberOfFiles</key>
        <integer>8192</integer>
    </dict>

    <!-- スロットリング(再起動の間隔、秒単位) -->
    <key>ThrottleInterval</key>
    <integer>60</integer>
</dict>
</plist>

newsyslog 設定ファイル​/​etc​/​newsyslog.d​/​nginx.conf

perl# logfilename                                      [owner:group]    mode count size when  flags [/pid_file] [sig_num]

# Nginxアクセスログ - 100MBまたは毎日0時にローテーション、30世代保持
/usr/local/var/log/nginx/access.log                nginx:staff      644  30    102400  @T00  GZN  /usr/local/var/run/nginx.pid  SIGHUP

# Nginxエラーログ - 日次ローテーション、14世代保持
/usr/local/var/log/nginx/error.log                 nginx:staff      644  14    *       $D0   GZN  /usr/local/var/run/nginx.pid  SIGHUP

# launchd標準出力ログ - 10MBで日次ローテーション、7世代保持
/usr/local/var/log/nginx/launchd.out.log           nginx:staff      644  7     10240   $D0   GZ

# launchdエラーログ - 10MBで日次ローテーション、7世代保持
/usr/local/var/log/nginx/launchd.error.log         nginx:staff      644  7     10240   $D0   GZ

Nginx メイン設定ファイル​/​usr​/​local​/​etc​/​nginx​/​nginx.conf

nginx# ワーカープロセスの実行ユーザー
user nginx staff;

# ワーカープロセス数(CPUコア数に合わせる)
worker_processes auto;

# エラーログの設定
error_log /usr/local/var/log/nginx/error.log warn;

# PIDファイルの場所
pid /usr/local/var/run/nginx.pid;

events {
    # 1ワーカーあたりの最大同時接続数
    worker_connections 1024;

    # 複数の接続を同時に受け付ける
    multi_accept on;

    # 効率的なイベント処理モデル(macOSではkqueue)
    use kqueue;
}

http {
    # MIMEタイプ設定
    include       mime.types;
    default_type  application/octet-stream;

    # ログフォーマット
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # アクセスログ
    access_log /usr/local/var/log/nginx/access.log main;

    # バージョン情報を非表示
    server_tokens off;

    # ファイル送信の最適化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # タイムアウト設定
    keepalive_timeout 15;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    # バッファサイズ制限
    client_body_buffer_size 128k;
    client_max_body_size 10m;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k;

    # gzip圧縮
    gzip on;
    gzip_vary on;
    gzip_min_length 1000;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # 追加の設定ファイルを読み込み
    include /usr/local/etc/nginx/conf.d/*.conf;
    include /usr/local/etc/nginx/sites-enabled/*;
}

サーバー設定ファイル​/​usr​/​local​/​etc​/​nginx​/​conf.d​/​default.conf

nginxserver {
    # ポート80でリッスン
    listen 80;
    server_name localhost;

    # ドキュメントルート
    root /usr/local/var/www;
    index index.html index.htm;

    # 文字コード
    charset utf-8;

    # メインロケーション
    location / {
        try_files $uri $uri/ =404;

        # HTTPメソッド制限
        limit_except GET HEAD POST {
            deny all;
        }
    }

    # 静的ファイルのキャッシュ設定
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # .htaccessや隠しファイルへのアクセス拒否
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # エラーページ
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/local/var/www;
    }
}

起動から運用までの流れ

設定ファイルを配置したら、以下の手順で Nginx を起動し、運用を開始します。

mermaidflowchart TB
    start["設定準備"] --> user["nginxユーザー作成"]
    user --> dir["ディレクトリ構築"]
    dir --> perm["権限設定"]
    perm --> conf["設定ファイル配置"]
    conf --> test["設定テスト"]
    test --> plist["plist配置"]
    plist --> load["launchdロード"]
    load --> verify["起動確認"]
    verify --> monitor["監視開始"]

ステップ 1: nginx ユーザーの作成

bash# nginxグループとユーザーを作成
sudo dscl . -create /Groups/nginx
sudo dscl . -create /Groups/nginx PrimaryGroupID 250
sudo dscl . -create /Users/nginx
sudo dscl . -create /Users/nginx UniqueID 250
sudo dscl . -create /Users/nginx PrimaryGroupID 250
sudo dscl . -create /Users/nginx UserShell /usr/bin/false
sudo dscl . -create /Users/nginx NFSHomeDirectory /var/empty
sudo dscl . -create /Users/nginx RealName "Nginx User"

ステップ 2: ディレクトリ構築

bash# 必要なディレクトリを作成
sudo mkdir -p /usr/local/etc/nginx/conf.d
sudo mkdir -p /usr/local/etc/nginx/sites-enabled
sudo mkdir -p /usr/local/var/log/nginx
sudo mkdir -p /usr/local/var/run
sudo mkdir -p /usr/local/var/www
sudo mkdir -p /usr/local/var/cache/nginx

ステップ 3: 権限設定

bash# 設定ディレクトリ
sudo chown -R root:wheel /usr/local/etc/nginx/
sudo chmod 755 /usr/local/etc/nginx/
sudo chmod 644 /usr/local/etc/nginx/nginx.conf

# ログディレクトリ
sudo chown -R nginx:staff /usr/local/var/log/nginx/
sudo chmod 755 /usr/local/var/log/nginx/

# ドキュメントルート
sudo chown -R nginx:staff /usr/local/var/www/
sudo chmod 755 /usr/local/var/www/

# キャッシュディレクトリ
sudo chown -R nginx:staff /usr/local/var/cache/nginx/
sudo chmod 700 /usr/local/var/cache/nginx/

ステップ 4: 設定テスト

bash# 設定ファイルの構文チェック
sudo /usr/local/bin/nginx -t

成功すれば以下のように表示されます。

swiftnginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

ステップ 5: launchd 設定

bash# plistファイルを配置
sudo cp com.nginx.server.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/com.nginx.server.plist
sudo chmod 644 /Library/LaunchDaemons/com.nginx.server.plist

# newsyslog設定を配置
sudo cp nginx.conf /etc/newsyslog.d/
sudo chown root:wheel /etc/newsyslog.d/nginx.conf
sudo chmod 644 /etc/newsyslog.d/nginx.conf

ステップ 6: サービス起動

bash# launchdにロード
sudo launchctl load /Library/LaunchDaemons/com.nginx.server.plist

# サービス起動
sudo launchctl start com.nginx.server

ステップ 7: 起動確認

bash# サービス状態を確認
sudo launchctl list | grep nginx

# プロセスを確認
ps aux | grep nginx

# ポート80がリッスンされているか確認
sudo lsof -iTCP:80 -sTCP:LISTEN

正常に起動していれば、以下のような出力が得られます。

yamlnginx    1234  0.0  0.1  2468  1024  ??  Ss    9:00AM   0:00.01 nginx: master process
nginx    1235  0.0  0.2  2468  2048  ??  S     9:00AM   0:00.02 nginx: worker process

ステップ 8: 動作テスト

bash# ローカルアクセステスト
curl -I http://localhost

# レスポンスヘッダーを確認
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 01 Jan 2025 09:00:00 GMT
Content-Type: text/html

サーバートークンが非表示になっており、バージョン情報が表示されていないことを確認しましょう。

監視とメンテナンス

本番環境では、Nginx の状態を継続的に監視し、問題が発生したら即座に対応する必要があります。

ヘルスチェックスクリプト​/​usr​/​local​/​bin​/​nginx-healthcheck.sh

bash#!/bin/bash

# ヘルスチェックスクリプト

LOG_FILE="/usr/local/var/log/nginx/healthcheck.log"
ALERT_EMAIL="admin@example.com"

# プロセスチェック
if ! pgrep -x nginx > /dev/null; then
    echo "[$(date)] CRITICAL: Nginx process not running" >> "$LOG_FILE"
    # launchdが自動的に再起動するので、ログ記録のみ
fi

# ポートチェック
if ! lsof -iTCP:80 -sTCP:LISTEN > /dev/null; then
    echo "[$(date)] CRITICAL: Port 80 not listening" >> "$LOG_FILE"
fi

# HTTPレスポンスチェック
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost)
if [ "$HTTP_CODE" != "200" ]; then
    echo "[$(date)] WARNING: HTTP response code is $HTTP_CODE" >> "$LOG_FILE"
fi

# ログファイルサイズチェック(100MB以上で警告)
ACCESS_LOG_SIZE=$(stat -f%z /usr/local/var/log/nginx/access.log)
if [ "$ACCESS_LOG_SIZE" -gt 104857600 ]; then
    echo "[$(date)] WARNING: access.log size is over 100MB" >> "$LOG_FILE"
fi

スクリプトに実行権限を付与します。

bashsudo chmod 755 /usr/local/bin/nginx-healthcheck.sh

cron で定期実行します。

bash# crontabを編集
sudo crontab -e

以下の行を追加して、5 分ごとにヘルスチェックを実行します。

perl# Nginxヘルスチェック(5分ごと)
*/5 * * * * /usr/local/bin/nginx-healthcheck.sh

ログ監視スクリプト​/​usr​/​local​/​bin​/​nginx-log-monitor.sh

bash#!/bin/bash

# エラーログ監視スクリプト

ERROR_LOG="/usr/local/var/log/nginx/error.log"
ALERT_LOG="/usr/local/var/log/nginx/alert.log"

# 直近1分間のエラーを検索
ERRORS=$(tail -n 1000 "$ERROR_LOG" | \
         grep "$(date -v-1M '+%Y/%m/%d %H:%M')" | \
         grep -E "\[error\]|\[crit\]|\[alert\]|\[emerg\]")

if [ -n "$ERRORS" ]; then
    echo "[$(date)] Errors detected in the last minute:" >> "$ALERT_LOG"
    echo "$ERRORS" >> "$ALERT_LOG"
fi

このスクリプトも cron で定期実行しましょう。

bash# crontabに追加(1分ごと)
* * * * * /usr/local/bin/nginx-log-monitor.sh

メンテナンスコマンド一覧

日常的なメンテナンスで使用するコマンドをまとめます。

#操作コマンド説明
1設定再読み込みsudo nginx -s reloadダウンタイムなしで設定を反映
2設定テストsudo nginx -t構文チェック
3サービス停止sudo launchctl stop com.nginx.serverプロセスを停止
4サービス開始sudo launchctl start com.nginx.serverプロセスを起動
5ログローテーションsudo newsyslog -v手動でログをローテーション
6ログ確認tail -f ​/​usr​/​local​/​var​/​log​/​nginx​/​access.logリアルタイムでログを監視
7プロセス確認ps aux | grep nginx実行中のプロセスを確認
8ポート確認sudo lsof -iTCP:80 -sTCP:LISTENポート 80 の使用状況を確認

設定変更後は、必ず以下の手順を踏みましょう。

bash# 1. 設定ファイルをバックアップ
sudo cp /usr/local/etc/nginx/nginx.conf /usr/local/etc/nginx/nginx.conf.bak

# 2. 設定を編集
sudo vi /usr/local/etc/nginx/nginx.conf

# 3. 構文チェック
sudo nginx -t

# 4. 問題なければリロード
sudo nginx -s reload

構文エラーがあった場合は、バックアップから復元します。

bash# バックアップから復元
sudo cp /usr/local/etc/nginx/nginx.conf.bak /usr/local/etc/nginx/nginx.conf
sudo nginx -s reload

まとめ

macOS で Nginx を本番級に運用するための設定方法を、launchd によるサービス管理、newsyslog によるログローテーション、適切な権限設計、そしてコード署名まで、実践的に解説してまいりました。

Linux とは異なる macOS 独自の仕組みを理解することで、安定した Nginx 運用が実現できます。特に重要なポイントを振り返りましょう。

  • launchd: plist ファイルで自動起動とプロセス監視を設定
  • newsyslog: ​/​etc​/​newsyslog.d​/​ に設定ファイルを配置し、自動ログローテーションを実現
  • 権限設計: nginx 専用ユーザーを作成し、最小権限の原則でセキュリティを強化
  • ポート対応: マスタープロセスを root で起動するか、pfctl でポートフォワーディング
  • コード署名: Gatekeeper 対応のため、可能であれば署名と公証を実施

これらの設定を適切に行うことで、macOS 上でも Linux 環境と同等の信頼性で Nginx を運用できるようになります。本記事の設定例を参考に、ぜひご自身の環境に合わせてカスタマイズしてみてください。

関連リンク