オペレーション全部自動化してしまい飽きた
セキュリティもパッチ適用もログ管理も監視もぜーんぶ自動化し終わった 飽きた…
掲示板機能の分離 ├─ Thread/Reply → 独立したboardアプリへ移行 ├─ 匿名投稿の「名前#トリップ」機能を実装 └─ URL・テンプレート参照を全て更新 収益化の仕組み ├─ AffiliateProductにcustom_html対応(バナー広告の直接埋め込み) ├─ show_in_feedフラグで、フィード内広告の対象を制御 └─ 10投稿ごとに自動で広告を挿入
Zのコミュニティサイトを、Androidアプリとしても使えるようにしました! Google Play正式リリース前のβテストとして、まずはフォロワーの皆さんに先行配布します。 📱ダウンロード: https://community.tokeisanheaven.uk/static/downloads/app-release-signed.apk ※Google Play以外からのインストールになるため、警告出るよ
このサイトを、Androidアプリとしても配布できるようにしました。今回は、PWA(Progressive Web App)として作っていたサイトを、TWA(Trusted Web Activity)という仕組みでAndroidアプリ化した手順を、実際につまずいた点も含めて書いていきます。 ■ そもそもTWAとは TWAは、既存のWebサイトを、ほぼコードを書かずにAndroidアプリとして包める、Google公式の仕組みです。アプリ内でChromeのエンジンをそのまま使い、通常のブラウザのようなアドレスバーを表示せずにサイトを表示できます。ネイティブアプリを1から書く必要がなく、今あるDjangoサイトの資産をそのまま活かせるのが最大の利点です。 前提として、TWA化する前にサイト自体をPWA化しておく必要があります。具体的には、アプリ名やアイコンを定義する「manifest.json」というファイルと、オフライン対応やプッシュ通知を担う「Service Worker」というJavaScriptファイルの2つを用意しました。 ■ Bubblewrapでのプロジェクト生成 TWA化には、Googleが提供する「Bubblewrap」というコマンドラインツールを使いました。Node.js製のツールで、事前にNode.jsとnpmが入っている環境なら、次のコマンドでインストールできます。 npm install -g @bubblewrap/cli 初期化コマンド(bubblewrap init)を実行すると、対話形式で、サイトのmanifest.jsonを読み込みながら、アプリ名・パッケージ名・テーマカラー・アイコン画像などを順番に質問されます。ここで注意したいのが、JDKとAndroid SDKのダウンロードです。まだ入っていない場合、Bubblewrap自身が自動でダウンロード・インストールしてくれますが、あわせて1GB近い容量とそれなりの時間がかかります。 ■ 署名鍵の扱いには要注意 初期化の最後に、アプリの署名に使う鍵(キーストア)を新規作成する場面がありました。ここで設定するパスワードと鍵ファイルは、今後そのアプリを更新するたびにずっと使い続ける、非常に重要なものです。紛失すると、二度と同じアプリとして更新できなくなり、最悪の場合は新しいアプリとして登録し直すしかなくなります。生成直後に、必ず安全な場所へバックアップしておくことを強くおすすめします。 初期化が終わったら、以下のコマンドでビルドします。 bubblewrap build これで、テスト用のAPKファイルと、Google Play提出用のAABファイルの両方が生成されます。 ■ サイトとアプリの信頼関係を証明する TWAでアドレスバーを完全に非表示にするには、「このアプリとこのサイトは同じ運営者が管理している」ことを証明する必要があります。これには「Digital Asset Links」という仕組みを使います。 bubblewrap fingerprint generateAssetLinks というコマンドで、署名鍵から自動的に証明用のJSONファイルが作られます。これを、サイトの「/.well-known/assetlinks.json」という決まった場所に設置する必要がありました。Djangoでは、robots.txtやads.txtと同じ要領で、TemplateViewを使って配信するようにしています。 最初、このJSONファイルの中身が空の配列になってしまう不具合に遭遇しました。原因は、鍵のフィンガープリント(証明書の指紋のようなもの)が、プロジェクトの設定ファイルにまだ登録されていなかったためでした。 keytool -list -v -keystore android.keystore -alias android というコマンドで鍵からフィンガープリントを取得し、 bubblewrap fingerprint add [取得した値] で明示的に登録し直すことで解決しました。 ■ 実機での動作確認 生成したAPKファイルを実際のAndroid端末にインストールしてみると、無事にアドレスバーのない、通常のアプリと同じ見た目で起動できました。Google Play以外からインストールする形になるため、初回だけ「提供元不明のアプリ」という警告が出ますが、設定から許可すればすぐにインストールできます。 ■ 今後について まずはこのAPKファイルを、SNSのフォロワー向けにβ版として直接配布する形にしました。Google Playへの正式リリースには開発者登録(登録料が必要)と審査が必要になるため、身内での反応を見てから、落ち着いて進めていく予定です。 なお、iPhone(iOS)には、AndroidのAPKのような形の自由な野良配布の仕組みが存在しません。iOSでは、Safariの「ホーム画面に追加」機能を使ったPWAとしての利用を案内する形に留めています。 今回、Webサイトとネイティブアプリの境界にある技術に触れてみて、Webの資産をそのままモバイルアプリの入り口として活かせる仕組みの便利さを実感しました。
個人で運営するサイトでも、公開する以上はセキュリティ対策が欠かせません。今回は、このサイトを守るために導入した仕組みについて書きます。 まず入れたのが「fail2ban」というソフトです。ログインを何度も間違えたり、明らかに不審なアクセスを繰り返すIPアドレスを、自動的に一定時間ブロックしてくれます。自分自身の作業用アドレスまで誤ってブロックされないよう、自宅のネットワークだけは対象外にする設定もあわせて行いました。 次に「ModSecurity」というWebアプリケーションファイアウォールを導入しました。SQLインジェクションやXSSといった、Webサイトへのよくある攻撃パターンを検知する仕組みです。まずは検知だけを行うモードで様子を見て、誤検知が少ないことを確認してから、本格的な防御に切り替えていく方針にしています。実際、長文投稿への対応中に、正規のリクエストまで誤検知されてしまう場面もあり、ルールを個別に調整しました。 管理画面についても、自宅のネットワークからしかアクセスできないよう制限をかけるなど、外部に露出させる範囲を最小限にする工夫も加えています。サーバー自体も、外部から直接ポートを開放せず、特殊なトンネル技術を使って必要な通信だけを中継する構成にしました。 セキュリティ対策は「これで完璧」という終わりがない分野です。段階的に対策を積み重ねていくことが、結局は一番の近道だと感じています。 もう一つ意識したのは、対策を入れすぎて正常な利用者まで不便にしてしまわないことです。実際、ファイアウォールの検知ルールが厳しすぎて、正規の投稿フォームが誤って弾かれてしまう場面がありました。安全性と使いやすさは、常に天秤にかけながら調整していく必要があるのだと学びました。 次回は、サイトの状態を見張る監視の仕組みについて書きます。
今回は、サイトを24時間見張り、自動で保守してくれる仕組みについて書きます。 サイトの状態を見張るために「Zabbix」という監視ソフトを導入しました。サイトが落ちていないか、サーバーのCPUやメモリ、ディスクの使用率が高すぎないかを常にチェックし、異常があればメールで知らせてくれます。クラウド環境と自宅サーバー環境、両方のサイトを同時に監視できるようにしています。 さらに、週に1回、サーバー全体のセキュリティ設定を自己診断するツールと、ウイルスやルートキットを検知するツールを自動実行するようにしました。これらのツールが検知した異常も、監視ソフトのログ監視機能と連携させて、自動でメール通知が飛ぶようにしています。 パッケージの更新(セキュリティパッチ)も、毎週決まった曜日の深夜に自動で適用され、再起動が必要な場合だけ自動的に再起動する仕組みにしています。ログファイルについても、たまり続けて容量を圧迫しないよう、古いものは自動的に圧縮・アーカイブし、一定期間を過ぎたら削除する仕組みを組み込みました。 こうして、なるべく手間をかけずに、安全な状態を保てる運用体制を整えました。普段は特に何もせず放っておいて、異常があったときだけ気づける体制になったことで、精神的な負担もかなり減りました。 監視の仕組みを作り込む過程では、権限の設定ミスでログファイルが読み込めず、サーバーが起動しなくなるという冷や汗をかく場面もありました。原因を1つずつ確認していくと、ファイルの権限だけでなく、OSのセキュリティ機構そのものの設定が意図せず変わっていたことが分かり、直すまでに何度もサーバーを行き来しました。 次回は、クラウドと自宅サーバーを併用する運用について書きます。
これまでの連載の最後に、このサイトをクラウドと自宅サーバーの両方で動かすことにした経緯について書きます。 このサイトは元々クラウドサービス上で動かしていましたが、途中から自宅にあるサーバーでも同時に動かすようになりました。自宅のインターネット回線を使ってサイトを公開しようとしたところ、契約している回線の仕組み上、外部から自宅サーバーに直接アクセスできない制限があることが分かりました。ポートを開放するという、よくある方法が使えなかったのです。 そこで採用したのが、サーバー側から外部に向けて接続を確立するタイプの技術です。ルーターの設定を一切変更せずにサイトを公開できる仕組みで、これを知ったときは目から鱗が落ちる思いでした。固定のアドレスで運用するために、独自ドメインも取得しています。 コードの管理も、クラウド環境用と自宅サーバー環境用でリポジトリを分け、誤って片方の変更がもう片方に影響しないようにしました。画像の保存先も、クラウド環境は外部ストレージサービス、自宅サーバーは大容量の内蔵ディスクと、環境ごとに切り替えられるようにしています。 自宅サーバーは停電やネットワークの一時的な不調で落ちてしまうことがあるため、監視の仕組みが特に重要になります。実際に運用中、原因不明の接続不良やサーバーの停止に何度か遭遇し、そのたびにログを読み解いて対処してきました。 クラウドと自宅、それぞれに向き不向きがありますが、両方を経験してみることで、Webサービスの裏側の仕組みについて、実感を持って理解できるようになったと感じています。今後も機能追加や改善を続けていく予定なので、また折を見て開発の様子を書いていきたいと思います。これで、このサイトの作り方シリーズは一区切りです。読んでくださってありがとうございました。
自宅サーバーでRHEL(Red Hat Enterprise Linux)を使ってWebサイトを公開したい人向けに、Red Hatデベロッパーアカウントの作成から、Apache httpdでのWebサーバー構築までの手順を、実際に使ったコマンドを交えてまとめます。一般的な環境を想定していますので、細部は自分の環境に合わせて読み替えてください。 ■ Red Hatデベロッパーアカウントの作成 まず、以下のサイトにアクセスしてアカウントを作成します。 https://developers.redhat.com/ メールアドレス、氏名などの基本情報を入力し、確認メールのリンクを踏めば登録完了です。法人名の入力欄がありますが、個人利用の場合は「Personal」や自分の名前を入れておけば問題ありません。 このプログラムで利用できるのは、正確には「Red Hat Developer Subscription for Individuals」という個人向けのサブスクリプションです。商用の本番環境での利用は想定されておらず、あくまで開発・学習目的での利用が前提となっている点は理解しておく必要があります。とはいえ、機能制限なくRHELのすべての機能を使えるため、自宅サーバーでの学習・検証用途には十分すぎるほどの内容です。 ■ RHELのインストール Red Hat公式サイトから、RHELのインストールISOイメージをダウンロードします。ダウンロードには、先ほど作成したデベロッパーアカウントでのログインが必要です。 ダウンロードしたISOイメージを、USBメモリに書き込んで起動ディスクを作成するか、仮想マシンで使う場合はそのままISOを読み込ませてインストーラーを起動します。 インストール中の設定でひとつ重要なのが、インストール完了後にシステムをRed Hatのサブスクリプションに登録することです。インストール完了後、以下のコマンドで登録します。 sudo subscription-manager register --username <デベロッパーアカウントのユーザー名> パスワードを求められたら入力してください。登録が成功すると、dnfコマンドでのパッケージインストールが可能になります。 登録状況は、以下のコマンドでいつでも確認できます。 subscription-manager status もし「Overall Status: Current」と表示されていれば、正しく登録が完了しています。逆に「Unknown」や「Invalid」と出る場合は、登録がうまくいっていない可能性があるため、再度登録コマンドを実行してみてください。 ■ システムの基本設定 まず、システム全体を最新の状態に更新します。 sudo dnf update -y タイムゾーンを日本時間に設定します。 sudo timedatectl set-timezone Asia/Tokyo ホスト名を設定しておくと、後々の管理がしやすくなります。 sudo hostnamectl set-hostname myserver 作業用のユーザーアカウントも、rootとは別に作成しておくことを強くおすすめします。日常的な操作をrootで行うのは、操作ミスによる被害範囲が大きくなるため避けるべきです。 sudo useradd myuser sudo passwd myuser sudo usermod -aG wheel myuser wheelグループに所属させることで、そのユーザーがsudoコマンドを使えるようになります。 ■ ファイアウォールの設定 RHELはデフォルトでfirewalldが有効になっています。Webサーバーを公開するには、httpとhttpsのポートを開放する必要があります。 sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --reload 現在開放されているサービスを確認するには、次のコマンドを使います。 sudo firewall-cmd --list-services もし特定のポート番号を直接開放したい場合(Apacheを標準の80番以外のポートで動かす場合など)は、以下のようにします。 sudo firewall-cmd --permanent --add-port=8080/tcp sudo firewall-cmd --reload firewalldはゾーンという概念で通信の許可範囲を管理しています。デフォルトでは「public」ゾーンが使われることが多いですが、現在使われているゾーンを確認したい場合は、次のコマンドで見られます。 sudo firewall-cmd --get-active-zones ■ Apache httpdのインストール いよいよApacheをインストールします。RHELの標準リポジトリからdnfで簡単に導入できます。 sudo dnf install -y httpd インストール後、サービスを起動し、OS起動時に自動起動するよう設定します。 sudo systemctl start httpd sudo systemctl enable httpd 正常に起動しているか確認します。 sudo systemctl status httpd 「active (running)」と表示されていれば成功です。 インストールされたApacheのバージョンを確認したい場合は、以下のコマンドを使います。 httpd -v RHELでは、設定ファイルは主に /etc/httpd/conf/httpd.conf に置かれ、追加の設定は /etc/httpd/conf.d/ 以下に個別のファイルとして置くのが一般的な運用です。設定ファイルを変更したら、必ず文法チェックをしてから再起動する習慣をつけておくと安心です。 sudo apachectl configtest sudo systemctl restart httpd 「Syntax OK」と表示されれば、設定ファイルの文法に問題はありません。 ■ SELinuxとの付き合い方 RHELはデフォルトでSELinuxが有効になっており、Apacheが特定のディレクトリにアクセスする際に制限がかかることがあります。基本的にはSELinuxを無効化せず、正しいコンテキスト(ラベル)を付与して運用するのが望ましい方法です。 例えば、公開したいファイルを標準の場所(/var/www/html)以外に置く場合、以下のようにコンテキストを設定します。 sudo semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?" sudo restorecon -Rv /data/www もし semanage コマンドが見つからない場合は、以下のパッケージを追加でインストールしてください。 sudo dnf install -y policycoreutils-python-utils 現在のSELinuxの動作モードは、次のコマンドで確認できます。 getenforce 「Enforcing」であれば、ポリシー違反となる操作は実際にブロックされます。「Permissive」であれば、違反は記録されるだけでブロックはされません。学習段階では、まずログを見ながら少しずつ正しいコンテキストを設定していく方が、後々の運用が楽になります。 もし何らかの操作がSELinuxによってブロックされている疑いがある場合は、以下のコマンドで関連するログを確認できます。 sudo ausearch -m avc -ts recent SELinuxを無効化する選択肢もありますが、本番運用では推奨されません。急場をしのぐ一時的な切り分けの手段として使う程度に留め、原因が分かったら正しいコンテキスト設定に戻すのが望ましい進め方です。 ■ 動作確認用のページを作成 Apacheのドキュメントルート(デフォルトでは /var/www/html)に、簡単なテストページを置いて動作確認します。 echo "<h1>Hello from Apache on RHEL</h1>" | sudo tee /var/www/html/index.html ブラウザで、サーバーのIPアドレスにアクセスして、ページが表示されるか確認します。 http://サーバーのIPアドレス/ もしページが表示されない場合は、ファイアウォールの設定、SELinuxのコンテキスト、Apacheのプロセスが実際に起動しているかを、順番に切り分けて確認していくことになります。特に、公開したいコンテンツを標準以外の場所に置いた場合は、SELinuxのコンテキスト設定を忘れがちなので注意してください。 ■ 独自ドメイン・SSL化への道筋 ここまでで、Apacheが正常に動作する状態が整いました。実際に外部公開する場合は、この先に以下のような作業が必要になります。 ・ドメインの取得とDNS設定 ・Let's EncryptなどによるSSL証明書の取得と設定 ・VirtualHostによる複数サイトの設定 ・アプリケーションサーバー(Django、Node.jsなど)との連携設定 これらは環境や目的によって大きく変わってくるため、また別の機会に詳しく書きたいと思います。 ■ まとめ Red Hatのデベロッパーアカウントを使えば、個人でも本格的なエンタープライズLinuxディストリビューションを無償で使うことができます。firewalldとSELinuxという、Ubuntu系のディストリビューションにはあまり馴染みのない仕組みに最初は戸惑うかもしれませんが、正しく理解して付き合えば、非常に安定した環境を構築できます。 特にSELinuxは、最初のうちは「エラーの原因が分からず、とりあえず無効化してしまう」という誤った対応をしがちですが、コンテキストという考え方さえ理解してしまえば、むしろ心強い防御レイヤーとして機能してくれます。多少遠回りに感じても、正しいコンテキストを都度設定していく習慣を身につけておくと、後々の運用で大きな安心材料になります。 ここまでの手順で、外部からアクセスできる基本的なWebサーバーの土台は整いました。実際にサービスとして公開していくには、この記事で紹介した基本設定の上に、ドメインの取得、SSL証明書の設定、アプリケーションサーバーとの連携など、さらにいくつかのステップが必要になります。それらについては、また機会を改めて書いていきたいと思います。
このサイトを自宅サーバー(RHEL + Apache httpd)で運用する中で、実際に使ってきたApacheの設定項目(ディレクティブ)を、体系立ててまとめてみます。公式ドキュメントは網羅的すぎて最初はとっつきにくいので、「実際に何のために使うのか」という視点で整理していきます。 ■ そもそもディレクティブとは Apacheの設定ファイル(httpd.confや、conf.d以下の個別ファイル)に書く、1行1行の設定項目のことをディレクティブと呼びます。「このURLパスにはこの権限が必要」「このドメインが来たらこのアプリを表示する」といった、Apacheの振る舞いを決める命令文だと考えると分かりやすいです。 ■ VirtualHost:1台のサーバーで複数サイトを扱う 同じサーバー上で、異なるドメインや異なるポートごとに別々のサイトを配信するための仕組みです。 <VirtualHost *:443> ServerName example.com ServerAlias www.example.com SSLEngine on SSLCertificateFile /etc/httpd/ssl/server.crt SSLCertificateKeyFile /etc/httpd/ssl/server.key </VirtualHost> ServerNameで、このVirtualHostがどのドメインへのリクエストに反応するかを指定します。ServerAliasは、追加で反応させたい別名(wwwありなし等)を指定する際に使います。 ■ WSGIDaemonProcess・WSGIScriptAlias:Pythonアプリとの連携 DjangoのようなPython製Webアプリケーションを動かすには、mod_wsgiというモジュールを使います。 WSGIDaemonProcess myapp python-home=/path/to/venv python-path=/path/to/project WSGIProcessGroup myapp WSGIScriptAlias / /path/to/project/project/wsgi.py WSGIDaemonProcessは、Apacheの本体プロセスとは別に、Pythonアプリ専用の子プロセスを立ち上げる設定です。python-homeには仮想環境(venv)のパス、python-pathにはDjangoプロジェクトのパスを指定します。WSGIScriptAliasは、どのURLパスにアクセスされたら、どのwsgi.pyファイルを呼び出すかを紐付けます。 なお、WSGIApplicationGroup %{GLOBAL} という設定を追加しないと、「populate() isn't reentrant」というエラーが出ることがあります。これは、複数のPythonアプリケーションが同じインタプリタ内で衝突しないようにする設定で、Django単体で運用する場合は基本的に付けておくとトラブルを避けられます。 ■ Alias:静的ファイルの配信場所を指定する 画像やCSSなど、Pythonを介さずそのまま配信したいファイル群のために使います。 Alias /static/ /data/static/ <Directory /data/static/> Require all granted </Directory> Aliasで「このURLパスへのアクセスは、実際にはこのディレクトリの中身を見せる」という対応関係を作ります。続くDirectiveブロックで、そのディレクトリへのアクセス許可を明示的に与える必要があります。 ■ Require:アクセス制御 誰がそのURLパス・ディレクトリにアクセスできるかを制御します。 <Location /admin/> Require ip 192.168.11.0/24 </Location> この例では、管理画面へのアクセスを、自宅LAN内のIPアドレス帯だけに制限しています。全世界に公開したくない管理系のパスには、このような制限をかけておくと安心です。全員に許可したい場合はRequire all grantedを使います。 ■ SSLEngine・SSLCertificateFile:HTTPS化 <VirtualHost *:443> SSLEngine on SSLCertificateFile /etc/httpd/ssl/server.crt SSLCertificateKeyFile /etc/httpd/ssl/server.key </VirtualHost> SSLEngine onで、そのVirtualHostにSSL/TLSによる暗号化通信を有効にします。証明書ファイルと秘密鍵ファイルのパスを、それぞれ指定します。自己署名証明書を使う場合、ブラウザに警告が出ますが、リバースプロキシ(Cloudflareなど)を前段に置いている場合は、オリジンサーバー同士の通信としては許容されることもあります。 ■ RewriteEngine・RewriteRule:URLの書き換え RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] httpでのアクセスを、httpsへ自動的にリダイレクトする、よくあるパターンです。RewriteCondで条件(この場合「HTTPSが使われていない場合」)を指定し、RewriteRuleで実際の書き換えルールを定義します。ただし、特定のパス(Zabbixの管理画面など)だけリダイレクトの対象から除外したい場合は、RewriteCondに除外条件を追加する必要があります。 ■ ModSecurity関連ディレクティブ:WAF(Webアプリケーションファイアウォール) SecRuleEngine On SecAuditLog /data/log/httpd/modsec_audit.log SecDebugLog /data/log/httpd/modsec_debug.log SecRuleEngineは、ModSecurityの動作モードを指定します。Onにすると実際に攻撃をブロックし、DetectionOnlyにすると検知だけ行いブロックはしません。運用開始直後は、誤検知が多くないか確認するためDetectionOnlyで様子を見て、問題なければOnに切り替えるという段階的な進め方がおすすめです。個別のルールを除外したい場合は、以下のように書きます。 SecRuleRemoveById 931120 SecRuleRemoveById 942360 長文投稿など、特定の入力パターンで実行時エラー(PCRE limits exceeded)が起きるルールがある場合、こうしてIDを指定して個別に無効化できます。 ■ ログ関連ディレクティブ ErrorLog /data/log/httpd/error_log CustomLog /data/log/httpd/access_log combined ErrorLogはApache自体のエラーや、アプリケーション側の例外(Djangoのトレースバックなど)が記録される場所です。CustomLogは、誰がいつどのURLにアクセスしたかというアクセスログを記録します。combinedというのは、記録するログの書式(フォーマット)の名前です。 ■ MPM(Multi-Processing Module)関連ディレクティブ <IfModule mpm_event_module> StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 0 </IfModule> Apacheが同時にどれだけのリクエストをさばけるかを制御する設定です。StartServersは起動時に立ち上げる子プロセスの数、ThreadsPerChildは1つの子プロセスが持つスレッド数、MaxRequestWorkersは全体で同時に処理できる最大リクエスト数です。サーバーのメモリ・CPUに余裕がある場合は、これらの数値を大きめに設定することで、アクセス集中時の余裕を持たせられます。逆に、小規模なサーバーで数値を大きくしすぎると、メモリ不足でサーバー全体が不安定になることもあるため、搭載メモリとの兼ね合いで調整する必要があります。 ■ セキュリティ関連ヘッダーのディレクティブ(Django側での設定が主だが参考として) Apache単体でも、以下のようなヘッダー付与用ディレクティブがあります。 Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" X-Frame-Optionsは、自分のサイトが他サイトの中にiframeとして埋め込まれることを防ぐ、クリックジャッキング対策の定番設定です。今回はアプリケーション側(Django)で同等の設定をしていますが、Apache側でも二重に設定しておくと、より確実な防御になります。 ■ まとめ Apacheの設定は、最初は項目数の多さに圧倒されますが、「誰に」「何を」「どう見せるか」という3つの軸で整理すると理解しやすくなります。VirtualHostとServerNameで「誰宛のリクエストか」を決め、AliasやWSGIScriptAliasで「何を見せるか」を決め、RequireやModSecurityで「どう制御するか」を決める、という構造を意識すると、設定ファイル全体の見通しが良くなるはずです。 今回紹介したディレクティブは、実際にこのサイトの運用の中で使ってきたものばかりです。設定ファイルをいじる際は、必ずapachectl configtestで文法チェックをしてから再起動する習慣をつけておくと、設定ミスによるサービス停止を防げます。