「Web」の版間の差分

提供:senooken JP Wiki
(mod_rewrite)
(Flags)
1,983行目: 1,983行目:
[https://httpd.apache.org/docs/current/ja/rewrite/ Apache mod_rewrite - Apache HTTP Server Version 2.4]
[https://httpd.apache.org/docs/current/ja/rewrite/ Apache mod_rewrite - Apache HTTP Server Version 2.4]


https://grok.com/share/c2hhcmQtMw%3D%3D_73b90b17-8db9-4bb4-ad4f-3a5e18c9e238
https://grok.com/share/c2hhcmQtMw%3D%3D_051d98f7-939d-4c82-977d-c30f506b61c7


リダイレクトを扱うモジュール。非常によく使うので重要。
リダイレクトを扱うモジュール。非常によく使うので重要。
2,001行目: 2,001行目:
  RewriteRule ^archives/([0-9]+)$ archives/detail.php?id=$1 [L]
  RewriteRule ^archives/([0-9]+)$ archives/detail.php?id=$1 [L]
  # 上記は /blog/archives/123 → /blog/archives/detail.php?id=123 になる
  # 上記は /blog/archives/123 → /blog/archives/detail.php?id=123 になる
===== RewriteRule =====
mod_rewriteのコア。マッチしたパターンを置換先にリダイレクトする。
RewriteRule Pattern Substitution [flags]
====== Flags ======
[https://httpd.apache.org/docs/current/ja/rewrite/flags.html RewriteRule Flags - Apache HTTP Server Version 2.4]
指定可能なフラグが大量にある。が、よく使うものは少数。よく使う準。
* L|last: これ以上ルールを処理しない。関数でいうreturn/exit/break相当。これを指定しない場合、上のほうのRewriteRuleで書き換えた結果を、後続のRewriteRuleで処理することになる。基本は1 RewriteRuleにつき1L。ほぼ常につける。
* QSA|qsappend: Query String Append。本来、書き換えする際、?%{QUERY_STRING}を自分で明示的にしない限り、クエリー文字列は破棄される。破棄せずに自動的に引き継いでくれる。リダイレクトするときに、クエリー文字列も引き継いでほしいことが多いのでよく指定する。ほぼ常につける。
* R=301: 外部リダイレクト。これを指定しない場合、内部リダイレクト (URLは変わらない)。
* NC|nocase: Patternのマッチの大文字小文字を無視する。
* B (escape backreferences): 変換前に非英数字をエスケープする。後方参照時に基本的に使う。URLのマッピング前に、URL内のエスケープを解除する。したがって、後方参照時に、エスケープが解除される。このフラグを適用すると、後方参照内の英数字以外がエスケープされる。例えば、検索フォームでx & y/zを入力すると、アドレスバーやリクエストはエスケープしてくれる。が、後方参照はエスケープを解除してしまうので、BがないとURLにx&y/zがそのまま登場して不正なURLになる。
* PT|passthrogh: Alias/ScriptAlias/Redirectを解釈したい場合に使用。
L(100%) > QSA(90%) > R(70%) > NC(50%) > B(40%) > PT(20%)
あまり使わない。
* UnsafeAllow3F: 基本は使わない。Apache v2.2までは、URLクエリー文字列内部に?がある場合、バックリファレンスで?がそのままだった。が、v2.4からはエンコードして%3Fにしている。この動きが困る場合だけつける。レガシー互換用。本来ならアプリで対応すべき内容。
[L,QSA] をデフォルトフラグに思っておくとよい。R/NC/B/PTは状況に応じて、状況にマッチしたら必須になる。


===== RewriteCond =====
===== RewriteCond =====

2025年10月14日 (火) 16:42時点における版

Other

Tool

いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。

localhost

RFC 6761 で規定。RFC 2606で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。

IPv4=127.0.0.1/IPv6=::1とされている。

DB vs. file

https://chatgpt.com/share/67f78855-b640-800b-84c9-ed3ada7fef48

データはアクセス元によって、速度や負荷が異なるらしい。それぞれ特徴がある。

  • ファイル (JSON/php):
  • インメモリーDB: Redis
  • RDB: 排他処理。検索・集計。書込用。

書き込みの最終はRDBとして、そこからよく使うものを、書き込みの少ないものを、インメモリーDBやファイルに引き上げるような感じがする。

Application

検索機能のGET/POST

検索機能にGETとPOSTのどちらを使うか?という議論がある。

データ登録するわけなじゃないのだから、GETがいいんじゃない?

POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。

GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。

ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。

レート制限対策

いろいろ方法がある。

  • cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
  • 配列を利用して、1回のリクエストでまとめて取得する。
  • インターバルを設ける。
  • HTTP 429/413を検知して、リトライする。

指数関数的バックオフ

wait_interval = base * 2^n +/- jitter
  • wait_interval は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
  • base は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
  • n は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、nの値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
  • jitter は 0 から base の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し wait_interval の合計に加算するか減算するか、ランダムで選択してください。

再送とリロード

https://chatgpt.com/c/67e25ec2-26bc-800b-acd9-0aa197476788

POSTなどデータ登録系のAPI呼び出しした際、そのままリロードすると、同じ登録処理が再送されてしまう。特に、URLクエリーで登録パラメーターを渡す場合など。

更新後に、リダイレクトでパラメーターを消す。これだと安全でシンプル。

あるいは、登録に使ったデータで、表示もする。ただ、処理失敗時や、キャッシュDBとの整合性がややこしいことがある。

https://grok.com/share/c2hhcmQtMw%3D%3D_6cd6ea6f-48b8-402a-9401-7edda0fded18

二重送信の対策がいろいろある。JavaScriptに依存しない方式。

  1. PRGパターン: フォーム送信後、サーバー側での処理完了後にリダイレクト (Post/Redirect/Getパターン)。これにより更新ボタン誤操作による再送信を防止。特に、URLクエリーで登録パラメーターを渡す場合などに有効。
  2. フォームトークンによる一意性確保: フォーム送信時に一意のトークンを発行し、サーバー側でトークンを検証、処理後に無効化または再生成。同一トークンは拒否。
  3. サーバー側でのリクエスト制限: 同一ユーザー・セッションからのリクエスト頻度を制限。セッションやDBに最後の送信時刻を記録。

1+2がシンプルで効果的とのこと。スパムが懸念される場合に、リクエスト制限を追加。

javascript前提でいいなら、submitで実装。

登録フォーム

https://grok.com/share/c2hhcmQtMw%3D%3D_9b8894da-350e-4de9-b51d-531f9eb40ce7

例えば、パスワード設定フォームを追加する場合など、何かの設定の設定フォームの実装方法。

password.php+password.tplがある。

GET password.phpでpassword.tplを表示。

フォームを入力してsubmitしたら、POST password.phpを呼び出し。

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['register'])) {とかでリクエストメソッドを確認。

POSTならパラメーターをチェックして、エラーならエラー表示。問題ないならindex.phpにリダイレクトとかすると、むやみにファイルが増えなくていい。

Naming

https://grok.com/share/c2hhcmQtMw%3D%3D_be0ed272-6be3-4b41-b654-859926dfd227

name属性の値はチェインケースがいい。HTMLの文脈だとチェインケースが主流。

URL

クエリー配列

やり方がいくつかある。

  1. CSV文字列で受取後分割: https://www.sakdor.net/test/?var=1,2,3 explode(",",$_GET[var]);
  2. 配列添字
    1. http://www.sakdor.net/test/?var%5B%5D=1&var%5B%5D=2&var%5B%5D=3
    2. http://www.sakdor.net/test/?var%5Ba%5D=1&var%5Bb%5D=2&var%5Bc%5D=3
    3. http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3

データが決まっているならcsvがシンプル。

CGI

https://chatgpt.com/c/67634332-a3b8-800b-87a2-e21bd21a1cfc

WordPressなどのWebアプリだとファイル拡張子が登場しない。これはいくつかの仕組みが組み合わさって実現されている。

  1. パーマリンク設定 によるクリーンなURL構造の生成。
  2. .htaccess(Apache)リライトルール によるURLの書き換えとルーティング。
  3. index.php を起点とする動的な処理。
  4. テンプレート階層 に従って適切なPHPファイルを呼び出す。

.htaccessでindex.phpにリダイレクトして、index.phpから全て処理している。これにより省略できている。

同じ用に、アプリ側が対応していれば、index.fcgiに全部リダイレクトして、パスを解釈してくれるなら、/でのアクセスもできる気がする。

apache - How can I run a FastCGI script in root url (/ - without path)? - Stack Overflow

スペースの扱い

https://grok.com/share/c2hhcmQtMw%3D%3D_9c2c3143-b190-42f7-a985-20444806187e

URLは、RFC3986に従って、特殊文字のエンコードが必要。スペースは特殊文字。

%20がスペースのエンコーディングだが、+はURLクエリーパラメーター (?key=value) 内のスペース表現で登場することがある。ただ、+はクエリーパラメーター以外の文脈ではスペースとして認知されない。%2Bはスペース時代の%エンコード。

基本的に、URLクエリーパラメーターに指定する場合、JavaScriptの場合encodeURIComponent (PHP urlencode=クエリー用、rawurlencode=パス用) でエンコードする。これで、スペースや+が適切にエンコードされる。

ただ、HTMLフォームでgetを使用する場合、Webブラウザーが自動的にクエリーパラメーターをapplication/x-www-form-urlencoded形式にするので、スペースが+になる。

HTTP

RFC 9110: HTTP Semantics

Content-Disposition

Content-Disposition - HTTP | MDN

RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。

multipart/form-data

rfc7578

ファイルアップロード用のMIME type。

リクエストヘッダー

Content-Type: multipart/form-data; boundary=--hogehoge

リクエストボディー

--hogehoge
Content-Disposition: form-data; name="user_name"
Content-Type: text/plain

test
--hogehoge
Content-Disposition: form-data; name="email"

sample@mail.com
--hogehoge
Content-Disposition: form-data; name="gender"

male
--hogehoge
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
Content-Type: image/jpeg

\xff\xd8\....
--hogehoge--

ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。

curlコマンドでPOSTする, 様々な形式別メモ |

curlでの送信理由。

-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。

curl -X POST -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

データとテキストを同時送信したい場合、-Fで複数指定する。

curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

curlだと上記のboundaryなどをうまくやってくれるのだと思う。

リクエストボディー全体をファイルデータにする場合。

curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

IP address

出典: 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット

自宅サーバーを行う際、固定IPアドレスが必要になる。

取得方法がいくつかある。

  • 契約しているプロバイダでオプションとして申し込む方法
  • 固定IPアドレスに対応しているSIMを契約する方法
  • VPNを利用した固定IPアドレスの提供会社を利用する方法

VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。

Authentication

認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。

Basic認証

出典: Basic認証 - Wikipedia

Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。

GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA==

盗聴や改ざんが簡単だが、シンプルという利点がある。

Basic認証のキャッシュを削除する(ログアウトする) | DevelopersIO

ログアウト時は、hoge@domainのようにパスワードを省略した任意のユーザー名でログインを試みて既存のログイン状況を上書きする模様。

Digest認証も共通。

Digest認証

Basic認証・Digest認証・Form認証をざっくり理解 #Security - Qiita

HTTP標準の認証。Basic認証とほぼ同じ。ただし、パスワードをハッシュ化している。そのため、DBのパスワードが流出した場合に比較的安全。

OAuth

Ref

OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。

以下が登場人物。

  • resource owner: あるサイトのユーザー。
  • resource server: あるサイトのユーザーのデータの保有サーバー。
  • clent: クライアントアプリ。リソースサーバーのデータを使用したい。
  • authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。

アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。

処理の流れ。

  1. client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
  2. client<-resource owner: Authorization Grant。
  3. client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
  4. client<-authorization server: Access Token
  5. client->resource server: Access Token。アクセストークンでアクセス。
  6. client<-resource server: Access Token

Consumer Key/Secret: アプリ識別用のID/PW。

Access Token: サイトにアクセスするためのパスワード。

API

REST

About

RESTとは?基本概念と設計原則を初心者向けに解説

https://grok.com/share/c2hhcmQtMw%3D%3D_ce6a55f0-0855-4a59-b94e-34a1060ee92f

Representational State Transfer。Webサービスの設計手法。状態を転送する。URLとHTTPメソッドを使って、リソースをやりとりする設計。CRUDなんかがこれ。

例えば、商品一覧は/itemsにアクセスGETして、単一商品は/items/1みたいな感じ。

URL=リソース、HTTPメソッド=操作というルールでAPIを設計する。直観的で再利用や保守もしやすいシステムになる。

例えば、セミナーの申し込みのような、動詞を伴う処理の場合。動作を名詞にして、その動作のPOSTみたいな形にする。

GET /api/seminars

GET /api/seminars/123/registrations/789

セミナーが複数絡んだりして複雑な場合や、シンプルにしたいなら、申込自体を独立リソースにする。

例えば、ログイン・ログアウトはセッションの作成・削除で考える。

POST /api/sessions

DELETE /api/sessions

サインアップは GET /users/new、実際の登録はPOST /usersとか。

バージョン

/api/v1とかでバージョン番号のプレフィクスを付けるのが一般的。

公開しなくて、内部的なapiで変更箇所を自分で全部対応できるなら、別になくてもいい。

破壊的変更時にv2などで上げる。

例えば、変更したくなったら、v1にオプションでパラメーターを追加して、ある程度たまった段階で、v2で任意だったのを必須にするとかする。

移行したら、v1の応答にDeprecation: trueとかSunset: 2026-01-01で通知するとか。

Routing

Webアプリを新しく作る際の画面構成。基本的にRoutingと一致のこと。

1機能1ルートみたいな感じ。あとはCRUDに対応したルート。オブジェクト指向になっているとなお良い。

  • /register
  • /login
  • /logout
  • /users
  • /users/books/
  • /my/books/
  • /books
  • /books/new
  • /books/:id

CSR形式のアプリの場合、サーバー側には/api/を前置したルートを用意して、そちらにGET/POSTで必要なデータ処理する感じ。

複数レコードの登録

複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ

既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?

REST WebAPIのプラクティス | yamarkz.com

delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。

パラメーター

json - REST API Best practices: args in query string vs in request body - Stack Overflow

パラメーターの指定に3種類ある。

  1. リクエストボディー
  2. クエリー
  3. パス

パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。

ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。

この原則に従うとシンプルだろう。

  • URIには長さの制限がある。
  • ボディー
    • 引数が非常に多い場合。
    • 画像などバイナリーデータ。
    • キー・値構造を持たない場合。
  • クエリー文字列
    • 引数を簡単に確認できる。
    • 共通の引数の場合。

API Server

認証

https://grok.com/share/c2hhcmQtMw%3D%3D_3f170c15-108d-44a3-bcc9-c4bfe545c9e9

APIサーバーでは、OAuthのような認証手順を一般的にとる。つまり、最初にトークンを発行する。

セッション情報

https://grok.com/share/c2hhcmQtMw%3D%3D_900d375c-0e8f-4765-be2a-514d504b6177

APIサーバーは通常、ステートレスな設計が推奨される。大量のリクエストが想定され、スケールアウトが必要になるので、セッション共有は扱いが複雑で不利になる。また、クライアントが多様で、他のサーバーからも利用されるので、クッキーに依存したセッション管理は向いていない。

そのため、トークンベースの認証が採用される。トークンにユーザーIDが埋め込まれていて、照合時にユーザーIDを取り出す方式が一般的。

それ以外だと、都度リクエストパラメーターを指定するとか。

レスポンス設計

https://grok.com/share/c2hhcmQtMw%3D%3D_de320f67-f064-4f8f-a147-cbf2e4594bcd

レガシーコードだと、全部200で応答本体に独自ステータスコードを持たせるというのがあったりする。

HTTPステータスコードは、リクエスト全体の成否を示す。クライアントが最初に確認する情報。Restful APIのベストプラクティス。

独自ステータスコードをHTTPステータスコードにも対応付けたらいい。それだけだからそんなに難しくない。

  • 400 Bad Request: リクエストパラメーターエラー時の一般。
  • 401 Unauthorized: 認証関係。
  • 403 Forbidden: 認証済みだが、特定リソースへのアクセス制限時。
  • 404 Not Found: 指定されたリソースが不在時。
  • 422 Unprocessable Entity: 必須パラメーター類はそろっているが、値が無効な場合 (負の値、不正な座標値)。
  • 500 Internal Server Error: DB接続エラー、SQL実行エラーなど、予期しないエラー発生時。
  • 503 Service Unavailable: 一時的なサーバーの問題。DBメンテナンス中、過負荷など。
  • 409 Conflict: リクエストがDBの状態と競合する場合。チェックイン済みの場所にチェックインとか。
  • 429 Too Many Requests: レートリミット送信。
  • 405 Method Not Allowed

後は、JSON APIというリクエストとレスポンスのボディーのJSONの標準形式があるので、これに準拠するとよさそう。

// 成功時
{
  "data": {
    "checkin_id": "12345",
    "timestamp": "2025-10-07T10:39:00Z",
    "latitude": 35.6895,
    "longitude": 139.6917
  }
}
// エラー時
{
  "errors": {
    "code": "1001",
    "message": "チェックインに失敗しました。指定された場所から遠すぎます。",
    "current_distance_meters": 1500,
    "max_allowed_distance_meters": 100
  }
}

トップレベル要素を配置することで、クライアントはこのプロパティーの有無で成否を判断できて処理が楽になるとか。まあ、そうか。

MVCだと、Modelがビジネスロジックで、エラーコードを定義することが多いので、ここでmapとかstaticメソッドを作ってやるとよさそう。

Swagger

About

API Documentation & Design Tools for Teams | Swagger

【初心者向け】Swaggerとは?シンプルに解説 - NRIネットコムBlog

API管理のためのツールセット。OpenAPI (旧Swagger API) というAPIの文書化の仕様に準拠したAPI文書の作成ツール。

具体的には以下の3ツールがある (Swagger Documentation | Swagger Docs)。

  • Swagger Editor: API文書作成のエディター。YAMLかJSON形式でAPIを記述する。
  • Swagger UI: APIを対話的に操作可能なエディター。Swagger Editorの生成結果的なもの。
  • Swagger CodeGen: 複数のプログラミング言語向けにクライアントやサーバーコードの自動生成ツール。

APIは外部から呼び出しに使われる都合、重要。正確で一貫性のある設計が求められる。

  • API設計を統一的な形式で記述でき、開発者間での形式のずれや誤解・不一致を防ぎ、一貫性のあるAPI開発が可能。
  • API文書を自動生成できる。

Install

Editor

[Swagger Editor] のオンラインエディターで始めるのが手っ取り早い。他に、VSCodeの拡張機能で記述する方法もある。

VSCodeだとswaggerで検索してヒットする [OpenAPI (Swagger) Editor] とか。

Visual Studio CodeでOpenAPI(Swagger) Editorを使用する #VSCode - Qiita

[Alt-P] (> OpenAPI SwaggerUI preview) でプレビュー表示できる。

OpenAPI

About
openapi: 3.0.4
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9

servers:
  - url: http://api.example.com/v1
    description: Optional server description, e.g. Main (production) server
  - url: http://staging-api.example.com
    description: Optional server description, e.g. Internal staging server for testing

paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML.
      parameters: # リクエストパラメータ 省略可能。
      - name: test
        in: query
        schema:
          type: string
      responses:
        "200": # status code
          description: A JSON array of user names
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string

以下が基本構成。

openapi: 3.0.4
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9

servers:
  - url: http://api.example.com/v1
    description: Optional server description, e.g. Main (production) server
  - url: http://staging-api.example.com
    description: Optional server description, e.g. Internal staging server for testing

paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML.
      parameters: # リクエストパラメータ 省略可能。
      - name: test
        in: query
        schema:
          type: string
      responses:
        "200": # status code
          description: A JSON array of user names
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string

pathsの中に、APIパスとHTTPメソッドと応答の記載が基本。

responses.content

responses.content以下にmimeType別に応答を書く。同じapiでも複数のmime typeを許容できるからだろう。ただ、実際はapplication/jsonだけのことが多い。

schema以下で応答の種類を書く。基本は以下のどちらかだろう。

              schema:
                type: array
                items:
                  type: string
# ["string"]
              schema:
                type: object
                properties:
                  data:
                    type: string
# {data: "string"}
リクエストパラメーター

parameters、requestBodyにリクエストパラメーターを記載。

# クエリーパラメータ
  /tests:
    get:
      summary: テストAPI(一覧)
      parameters:
      - name: data
        in: query
        schema:
          type: string
  /tests:
    post:
      summary: テスト登録API
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
Components Section

Swaggerを使うことのかなり大きな利点。Components。

APIは、APIのルートパスのオブジェクトを返したり、受け付けたりする。パスごとにこれを何回も書くことになる。SwaggerではこれをComponentとして定義しておいて、その参照で記述を省略できる。

components:
  schemas:
    object名:
      type: object
      properties:
        プロパティ1:
          type: string
          format: string
          description: "プロパティ1の説明"
          example: "プロパティ1の例"
        プロパティ2:
          type: string
          format: string
          description: "プロパティ2の説明"
          example: "プロパティ2の例"
      required:
        - プロパティ1
        - プロパティ2
content:
  application/json:
    schema:
      $ref: '#/components/schemas/object名'

こんな感じで参照して流用できる。

Using $ref

Using $ref | Swagger Docs

APIの文書作成時に、リソースを複数で参照したいことがある。OpenAPI 3.0で相互参照機能が導入された。

$refキーワードを使う。

components:
  schemas:
    User:
      properties:
        id:
          type: integer
        name:
          type: string
responses:
  "200":
    description: The response
    schema:
      $ref: "#/components/schemas/User"

定義と参照を上記のように行う。

$refはJSON Reference (JSON pointer) 記法になっている。#以降はファイル内参照を意味する。先頭の#で現在のファイル。

$ref: 'document.json#/myElement' のように記載することで、別のファイル内のコンポーネントを参照できる。

どこでも使えるわけではない。値として使える場所にだけ使える。例えば、以下のようにパスのところに直接指定はできない。

openapi: 3.0.4

# Incorrect!
info:
  $ref: info.yaml
paths:
  $ref: paths.yaml
paths:
  /users:
    $ref: "../resources/users.yaml"
  /users/{userId}:
    $ref: "../resources/users-by-id.yaml"

値の文脈としてしか使えないので、パスの中身として使う。

Escape Characters
Character Escape With
~ ~0
/ ~1

エスケープ文字が独特なので注意する。

/blogs/{blog_id}/new~posts
$ref: "#/paths/~1blogs~1{blog_id}~1new~0posts"
Example

https://grok.com/share/c2hhcmQtMw%3D%3D_e2b6d5e1-dd0d-4412-8858-a99c09f15a0c

$ref記法を使うことで、ファイル分割できる。

JSON Referenceでリソースを直接参照することで対応する。

openapi.yml

openapi: 3.0.3
info:
  title: Sample API
  version: 1.0.0
paths:
  /users: {$ref: './paths/users.yaml#/paths/~1users'}
components:
  schemas:
    User: {$ref: './paths/users.yaml#/components/schemas/~1User'}
    # 必要なら共通のスキーマを別ファイルで管理
    $ref: './components/schemas.yaml#/schemas'

paths/users.yml

paths:
  /users:
    get:
      summary: ユーザー一覧を取得
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
  /users/{id}:
    get:
      summary: ユーザー詳細を取得
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
      required:
        - id
        - name

こんな感じで、ファイルに必要なものを全部記載して、$refでリソースを参照することで、完全に分離できる。

Grouping Operations With Tags

Grouping Operations With Tags | Swagger Docs

tags指令で、複数の別のAPIをグループ化できる。

tags:
    -name

Data Models

Supported JSON Schema Keywords

OpenAPI 3.0はJSON Schema Specificationの部分セットを拡張して使っている。

以下のキーワードはJSON Schemaと同一。

以下のキーワードは微修正して対応。

  • type – the value must be a single type and not an array of types. null is not supported as a type, use the nullable: true keyword instead.
  • format – OpenAPI has its own predefined formats and also allows custom formats.
  • description – supports CommonMark syntax for rich text representation.
  • items – must be present if type is array. The item schema must be an OpenAPI schema and not a standard JSON Schema.
  • properties – individual property definitions must follow OpenAPI schema rules and not standard JSON Schema.
  • additionalProperties – the value can be a boolean (true or false) or an OpenAPI schema.
  • default – the default value must conform to the specified schema.
  • allOf – the subschemas must be OpenAPI schemas and not standard JSON Schemas.
  • oneOf – the subschemas must be OpenAPI schemas and not standard JSON Schemas.
  • anyOf – the subschemas must be OpenAPI schemas and not standard JSON Schemas.
  • not – the subschema must be an OpenAPI schema and not a standard JSON Schema.

Adding Examples

リクエストパラメーターや、レスポンスボディーの例を記載できる。

exampleかexamples (複数) を使う。

parameters:
  - in: query
    name: status
    schema:
      type: string
      enum: [approved, pending, closed, new]
      example: approved # Example of a parameter value
parameters:
  - in: query
    name: limit
    schema:
      type: integer
      maximum: 50
    examples: # Multiple examples
      zero: # Distinct name
        value: 0 # Example value
        summary: A sample limit value # Optional description
      max: # Distinct name
        value: 50 # Example value
        summary: A sample limit value # Optional description

exampleは例が1この場合にだけ使える。

examplesは例が複数ある場合。区別できるようにまず名前があって、その下にvalueの下にプロパティーなどを記載する。

valueの部分はxml/htmlとかにもできる。リクエスト、レスポンスの文脈だとvalueで十分。

Other

returnCode

https://grok.com/share/c2hhcmQtMw%3D%3D_682b0476-5ab3-449c-a956-9385962c66ce

HTTPステータスコードじゃなくて、レスポンス本体のカスタムコードで、APIの結果を返すAPIがあったりする。これのSwaggerでの表現方法。

enumとdescriptionで記載する。

paths:
  /example:
    post:
      summary: カスタムレスポンスコードのサンプルAPI
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                input:
                  type: string
      responses:
        '200':
          description: リクエストが正常に処理されました。returnCodeで結果を確認してください。
          content:
            application/json:
              schema:
                type: object
                properties:
                  returnCode:
                    type: integer
                    description: |
                      以下の対応。
                      - 000000: 正常終了
                      - 200001: 申し込み済
                      - 990001: パラメータエラー
                      - 999999: API実行エラー
                    enum: [0, 1, 2, 3]
                    example: 0
                  message:
                    type: string
                    description: 処理結果の詳細メッセージ
                    example: "Operation completed successfully"
              example:
                returnCode: 0
                message: "Operation completed successfully"
        '500':
          description: サーバー内部で予期しないエラーが発生しました。
          content:
            application/json:
              schema:
                type: object
                properties:
                  returnCode:
                    type: integer
                    description: 処理結果を示すコード(この場合はサーバーエラー)。
                    example: 3
                  message:
                    type: string
                    example: "Internal server error"

descriptionで箇条書きで記載。箇条書きのために、descriptionの直後に|を入れて改行リテラル表記にする。それと並行してenumで値のパターンを定義する。

HTML出力

HTMLの出力までしたい場合、npmが必要。

いくつか方法がある。redocly/cliが悪くない。

npm install -g @redocly/cli
redocly build-docs --output index.html base.yml

こんな感じでswaggerのyamlファイルをindex.htmlに出力できる。

JSON Schema

About

JSON Schema

JSON Schemaとは?便利な生成方法をご紹介!

好きに記載可能なJSONに対して、JSONデータの構造とバリデーションルールを定義するための言語・仕様。これにより、JSONを使う入出力に対して、形式を定義できる。バリデーションなどを自動チェックできたりする。文書の自動生成や、データ変換などにも使える。

JSON Schema自体もJSONになっている。

Swaggerでのリクエスト・レスポンスボディーの定義などで採用されている。

例えば、プロパティーの存在、必要性。データの型、値の範囲などを検証できる。プロパティーの存在だけでも意味がある。

Example

{
  "name": "John Doe",
  "age": 30,
  "email": "john.doe@example.com",
  "address": {
    "street": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001"
  },
  "phoneNumbers": ["123-456-7890", "987-654-3210"]
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer",
      "minimum": 18
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "address": {
      "type": "object",
      "properties": {
        "street": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string",
          "maxLength": 2
        },
        "zip": {
          "type": "string",
          "pattern": "\\d{5}"
        }
      },
      "required": ["street", "city", "state", "zip"]
    },
    "phoneNumbers": {
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "\\d{3}-\\d{3}-\\d{4}"
      }
    }
  },
  "required": ["name", "age", "email", "address", "phoneNumbers"]
}

基本はtype: objectを記載して、properties以下にプロパティー名とtypeを定義する感じ。

type=arrayの場合はitems

重要なプロパティー

  • required
  • type
  • properties: type=object時
  • properties.<key>
    • type: 該当keyの型。
    • pattern: type=string時に使う、パターン。
    • minLength/maxLength: type=string時の文字数。
    • minimum/max: 数値系の最小・最大値。
  • items: type=array時

Reference

JSON Schema reference

JSON data types

JSON Schema - Type-specific Keywords

typeで指定可能な型がある。

  • array
  • boolean
  • null
  • numeric types (integer/number): integerは整数のみ。numberは整数+浮動小数点数。
    • multipleOf: 指定した数値の倍数である制約。
    • minimum/maximum: 最小値、最大値。
    • exclusiveMinium/exclusiveMaximum: 最小値、最大値 (指定値を含まない、<>相当)。またはtrueを指定するとminimum/maximumが含まない値に変わる。
  • object
  • regular expressions
  • string

Schema annotations and comments

JSON Schema - Schema annotations and comments

注釈とコメントがある。必須ではない。JSONスキーマの追加情報の提供に使われる。

Annotations

JSON Schema - Annotations

  • title
  • description
  • default
  • examples
  • readOnly
  • writeOnly
  • deprecated

JSON API

Web APIにはJSONベースのフォーマットを使おう #WebAPI - Qiita

Web APIでやりとりするJSONの記述方法の書式の一つ。

JSON:API — A specification for building APIs in JSON

{
  "data": {
    "type": "checkin",
    "id": "12345",
    "attributes": {
      "timestamp": "2025-10-07T10:37:00Z",
      "latitude": 35.6895,
      "longitude": 139.6917
    }
  },
  "meta": {
    "processed_at": "2025-10-07T10:37:00Z"
  }
}
{
  "errors": [
    {
      "status": "400",
      "code": "1001",
      "title": "Check-in failed",
      "detail": "The specified location is too far away.",
      "source": {
        "parameter": "latitude"
      },
      "meta": {
        "current_distance_meters": 1500,
        "max_allowed_distance_meters": 100
      }
    }
  ]
}


Network

環境変数

https://grok.com/share/c2hhcmQtMw%3D%3D_1fce8739-56a3-47a5-8a8c-55d209a0b37b

ネットワーク関係のツールは、いくつか共通の環境変数を参照する。curlで定義されている環境変数を流用して参照していることが多い。

  • poxy関係: http_proxy/https_proxy/no_proxyは重要
    • http_proxy
    • htttps_proxy
    • no_proxy
    • ftp_proxy
    • all_proxy
    • RSYNC_PROXY

内部リクエスト時には、proxy設定があると、プロキシーサーバーにリクエストに行って不都合起きることがあるので注意する。

ssh

ssh-addの自動登録

ssh agentに秘密鍵の登録は以下のコマンド。

ssh-add <秘密鍵のpath>

ただし、上記コマンドは再起動すると登録が消えるので毎回必要。

~/.ssh/configに以下の内容を記入しておくと、次回からkeychainから自動で読み込まれるらしい (macOS で再起動しても ssh agent に秘密鍵を保持させ続ける二つの方法 #SSH - Qiita)。

Host *
  UseKeychain yes
  AddKeysToAgent yes

うまくいかなかった。

ssh-addをPC起動する度に自動的に実行させるための設定 | AIFAN

id_rsaの場合はIdentityFileを省略できるが、それ以外は指定が必要な模様。

Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519

ssh経由でのリダイレクト出力

bash - How to remotely write to a file using SSH - Super User

ssh経由で標準入力内容からファイルをリダイレクトで作成したいことがある。

sshのコマンド部分を文字列にすればOK。

ssh user@remotehost -T "cat > /remotefile.txt" <<-EOT
Some text
EOT

-Tで擬似端末を無効にしている。

パスフレーズの省略

SSH多段接続時とgit cloneでSSH鍵参照時に、パスフレーズを要求される。毎回要求されるのが手間。これを省略する方法がある。 ~/.ssh/configに以下の設定を記述する。

Host *
 AddKeysToAgent yes
 UseKeychain yes
 IdentityFile ~/.ssh/id_ed25519
  • AddKeysToAgent=yesにすると、ssh-agentの実行時に自動的に鍵を追加する。
  • UseKeychain=macOS専用。OSのキーチェーンからパスフレーズの検索を試みる。
  • IdentityFile=SSH秘密鍵の絶対パス。デフォルトは~/.ssh/id_rsa。

上記3点で自動入力を試みる。 macOSで行う分には上記だけでパスワードは聞かれない。これをリモートでもやりたいなら、ssh-agentに登録が必要。 ログイン時に1回実行してくれたらいいので、ログインシェルの設定の~/.bash_profileに以下を記述。

echo 'ssh-add --apple-use-keychain' >>~/.bash_profile

これで端末の起動時に鍵を自動登録してくれるので、リモートでもパスフレーズを要求されない。

ssh_config

ssh_config(5): OpenSSH SSH client config files - Linux man page

重要な設定・構文がある。

TOKENS

macのman ssh_configに詳しい。

使用可能な指令が限定されている。

HostName (Macのみ)

  • %h=リモートホスト名。Hostの指定部。
  • %p=リモートポート。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

ssh example.comなどを実行すると、IPアドレスの振り直しなどで、ホストの公開鍵が変わっていた場合、中間者攻撃への対策として失敗する。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:.
Please contact your system administrator.
Add correct host key in /Users/z.ken.senoo/.ssh/known_hosts to get rid of this message.
Offending RSA key in /Users/z.ken.senoo/.ssh/known_hosts:1
Host key for [example.com]:3023 has changed and you have requested strict checking.
Host key verification failed.
Connection closed by UNKNOWN port 65535
Connection closed by UNKNOWN port 65535

$HOME/.ssh/known_hostsの該当行を削除すれば解決する。以下のコマンドでも対応してくれる。

ssh-keygen -R example.com

いや、うまくいかない。~/.ssh/known_hostsに以下の該当ドメインの除外設定が必要な模様。

@cert-authority example.com ssh-rsa

sshd(8) - OpenBSD manual pages」に記載がある。

The marker is optional, but if it is present then it must be one of “@cert-authority”, to indicate that the line contains a certification authority (CA) key, or “@revoked”, to indicate that the key contained on the line is revoked and must not ever be accepted. Only one marker should be used on a key line.

...

When performing host authentication, authentication is accepted if any matching line has the proper key; either one that matches exactly or, if the server has presented a certificate for authentication, the key of the certification authority that signed the certificate. For a key to be trusted as a certification authority, it must use the “@cert-authority” marker described above.

https://chatgpt.com/c/67f321e3-3b78-800b-b263-3e7169488367

通常、known_hostsには、接続済みのホストの公開鍵を記録し、次回以降の接続時の確認に使う。ただ、この場合、IPアドレスが動的に変更する場合や、鍵が頻繁に変更される場合に、警告になる。この対策として、@cert-authorityで、同じ行のホスト鍵を署名したCA鍵を信頼する。これにより、同一のCAの複数ホストを一括で信頼する。

curl

HTTPの通信のコマンドラインでの確認でよく使う。

Basic

curl - Tutorial

  • -X: メソッド指定
  • -d/--data-urlencode: リクエストボディー (key=value)を指定。-X POSTも自動指定になる。
curl -H "Content-Type: application/json" -d '{"name":"佐藤", "mail":"sato@example.com"}' localhost:5000/api/v1/users\
curl -H "Content-Type: application/json" -d @body.json localhost:5000/api/v1/users\

JSONで送信する場合、ヘッダー指定が必須。

*-F: multipart/formのform指定。

curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
  http://www.example.com/postit.cgi

@でfilename相当の指定。;でmime typeも指定できる。

@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。

curl: (60) SSL certificate problem: self-signed certificate

Ref: curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI.

--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。

curl: Failed writing body

pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu

以下のようにhead -n 1を指定するとcurlがエラーを出力する。

curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"         -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"         https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0 | head -n 1
curl: Failed writing body

curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。

対策は、curl -sで出力を抑制するとのこと。これで解決。

Teleport

踏み台サーバー (Jump server/Jump host) をよりよく管理するためのサーバーソフトウェア。

アクセスログなどを一元管理できる。商用版とオープンソース版がある。

基本的にteleportのサーバーを一度経由して、各種の踏み台サーバーにアクセスする。経由先が1個増えるが、そのおかげで監査ログを取得できたり、権限などを一括管理できる。

ただ、teleportで監査ログを残すには、基本的にtshを経由する必要があり、既存のIDEなどのssh想定のソフトだと工夫が必要。tsh経由でやったり、rsyncで間にtshを挟むような工夫が必要。

Install

How to configure SSH Certificate-Based Authentication

[Download Teleport: Secure and Easy Infrastructure Access | Teleport] から自分のパソコンのtshをインストールする。

以下の環境変数を設定する。

  • TELEPORT_AUTH:
  • TELEPORT_LOGIN:
  • TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。

tsh

teleportのコマンドラインクライアント。

tsh loginでteleportにログインする。

環境変数

tsh CLI reference | Teleport Docs

  • TELEPORT_AUTH:
  • TELEPORT_LOGIN:
  • TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。

上記3個が特に重要。

ProxyJump+ProxyCommand

How To Use SSH ProxyJump and SSH ProxyCommand

https://goteleport.com/blog/ssh-proxyjump-ssh-proxycommand/

~/.ssh/config のProxyJumpとProxyCommandの違いを整理する。

どちらも中間サーバーを経由したリモートサーバーアクセスの指令。

  • ProxyJump: 最も簡単な方法。OpenSSH v7,5以上で使用可能。中間サーバーでポート転送対応が前提条件。ProxyJumpは内部でProxyCommandを使う。
  • ProxyCommand: ProxyJump搭乗前の方法。中間サーバーを介して標準入力と標準出力を転送して機能。

ProxyJumpの方が現代的だが、ProxyCommandの方が柔軟性が高い。

ProxyJumpの使用例。

ssh -J <jump server> <remote server>ssh -J <jump server1>,<jump server2>,<jump server3> <remote server>

ProxyCommand

ssh -o ProxyCommand="ssh -W %h:%p <jump server>" <remote server>

~/.ssh/configの例。

Host remoteserver

 HostName 192.168.200.200

 User dev

 IdentityFile ~/.ssh/<your_key>

 Port 2048


 ## sample for ProxyJump

 ProxyJump user@<jumpserver>


 ## sample for ProxyCommand

 ProxyCommand ssh -W %h:%p <jumpserver>

ssh remoteserver で<jumpserver> 経由でremoteserverに接続できる。

一般的に、ProxyJumpが推奨される感がある。ただ、teleportを導入している場合、ProxyJump/ProxyCommandを使うと、tshを経由していないのでteleportにログが残らないらしい。

tsh経由ssh

ProxyJump/ProxyCommandを使わない場合、以下の形式でtshを使ってアクセスするのが基本。

tsh ssh 踏み台サーバーホスト名

tsh sshでteleportサーバーが管理している踏み台サーバーが見えるので、そこに接続できる。tshの後のsshは基本的に通常のsshと同じなので、sshの後にsshのコマンドを連鎖でき、対象サーバーにも一発でアクセスできる。

tsh ssh -At <jump host> ssh -A <target host>

-tでttyに繋いで標準入出力を接続。-Aはフォワーディング。ローカルのssh-addの情報などを連携できる。

<jump host>の~/.ssh/configを用意しておくことで、<target host>にホスト名を指定したりできる。

ProxyJump/ProxyCommandと異なり、これだとちゃんとログを残せる。

tsh経由scp

tsh経由の踏み台サーバーへのファイル転送はやや工夫が必要。

tsh scpというコマンドが一応ある。が、これはネストなどには未対応。やる場合、以下のように2回実行になる。

FR=test.file TO=/path/to/test.file
tsh scp $FR <jump host>:$TO; tsh ssh -At <jump host> scp $TO <target host>:$TO

高ではなく、rsyncを使えば一発でいける。

rsync -e "tsh ssh -A <jump host> ssh" ./test.file <target host>:~/

これが基本。

PhpStorm

JetBrains SFTP | Teleport Docs

teleportの公式にマニュアルがあるが、記述が非常に不親切。これだと踏み台サーバーにしかアクセスできない。その先にアクセスできない。

多段SSHの設定を残しておいて、ファイル転送だけrsyncで行う形になる。

PhpStormのSSH configurationsのホスト名がスクリプトの引数に渡されるので、踏み台からAWSにsshでログインするホスト名やパソコンの~/.ssh/configのHostとの一致必要な点に注意する。

USERNAME=
IPV4=
VPCID=
cat <<-EOT >>~/.ssh/config
Host $VPCID
  ForwardAgent yes
  User $USERNAME
  ServerAliveInterval 30
  SendEnv -LC_* -LANG
  ProxyJump $USERNAME@teleport.security:3023
   
Host $USERNAME
    ForwardAgent yes
    ProxyJump $VPCID:22
    User $USERNAME
    Hostname $USERNAME.example.com
    ServerAliveInterval 30
    SendEnv -LC_* -LANG
   
Host $USERNAME.$VPCID
    # for automatic upload by PHPStorm
    LocalForward 22224 $USERNAME.$VPCID:22
    # for XDebug
    RemoteForward 9000 localhost:9000
    ForwardAgent yes
   
Host db-*
  HostName $IPV4
  LocalForward 3307 localhost:22
  ProxyCommand ssh $VPCID -W %h:%p
  ForwardAgent yes
   
Host *
    AddKeysToAgent yes
    PasswordAuthentication no
    User $USERNAME
    ForwardAgent yes
    ServerAliveInterval 30
    IdentityFile ~/.ssh/id_ed25519
    # for macOS
    UseKeychain yes
EOT

こんな感じの多段SSHの設定を用意。 踏み台サーバーにも同じホスト名でアクセスできるように、以下のような内容の~/.ssh/configをまだならば設定しておく。

AWS_HOSTNAME=

IPV4=

VPCID=

tsh ssh -A $VPCID "cat >>~/.ssh/config" <<-EOT

Host $AWS_HOSTNAME

 HostName $IPV4

EOT


rsync executable

rsyncで使用する (-eオプション)、以下の内容のシェルスクリプトを作成して実行権限を付与して任意の場所 (例: ~/project/tsh_ssh.sh) に配置する。

cd ~/project/

cat <<-'EOT' >tsh_ssh.sh

tsh ssh -A <jump host> ssh $@

EOT

chmod +x tsh_ssh.sh


PhpStorm設定

PhpStormで以下を設定する。

  • [Tools]-[Deployment]-[Configuration]
  • [+]-[SFTP]
  • [Create New Server]-[New server name: 任意の名前 (例=rsync)]-[OK]
  • [Connection] タブを以下に設定。
    1. Type=SFTP
    2. SSH configuration=以下を設定。
      1. Host: <ホスト名> (例: ~/.ssh/configと踏み台サーバーの~/.ssh/configのホスト名と同じにする)
      2. User name: ユーザー名
      3. Port: 22
      4. Authentication type: OpenSSH config and authentication agent
    3. Root path=転送先のベース。
    4. [☑️Use Rsync for download/upload/sync]
    5. Rsync Settings=以下を設定。
      1. Shell executable path=tsh_ssh.shのパス (例=~/project/tsh_ssh.sh)
  • [Mappings] タブを以下に設定。
    1. Local path: ローカルパソコンのディレクトリー
    2. Deployment path: /
    3. Web path: /
  • [Settings]-[Build, Execution, Development]-[Development]-[Options]-[Upload changed files automatically to the default server]=[On explicit save action]
    1. ☑️Delete remote files when local are deleted

以上で完了。後は同期したいファイルをPhpStormで開いて、右クリック-[Deployment]-[Upload to]/[Download from] でファイル転送できる。

[☑️Use Rsync for download/upload/sync] のチェックを外せば、rsyncを使わないファイル転送になる。

Wireshark

TLS

Ref: SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー.

Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。

[Preferences]-[Protocols]-[TCP] を選ぶ。

  • ☑Allow subdissector to reassemble TCP stream
  • ☑Reassemble out-of-order semgemnts

上記をチェックしておく。デフォルトでチェックされていた。

続いて、セッションごとのPre-Master Secretを登録する。

Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。

以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。

export SSLKEYLOGFILE=/tmp/sslkey.log

Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。

Other

ネットワーク名

CentOS 7のネットワーク名「enp1s0」という文字列の謎に迫る #CentOS - Qiita

enp1s0とか最近のGNU/Linuxのネットワーク名が意味不明。

ソースコードに命名規則がある。

 * Two character prefixes based on the type of interface:
 *   en -- ethernet
 *   sl -- serial line IP (slip)
 *   wl -- wlan
 *   ww -- wwan
 *
 * Type of names:
 *   b<number>                             -- BCMA bus core number
 *   ccw<name>                             -- CCW bus group name
 *   o<index>[d<dev_port>]                 -- on-board device index number
 *   s<slot>[f<function>][d<dev_port>]     -- hotplug slot index number
 *   x<MAC>                                -- MAC address
 *   [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
 *                                         -- PCI geographical location
 *   [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
 *                                         -- USB port number chain
  • en: ethernet (有線LAN)
  • wl: wlan
  • p1: PCI bus 1
  • s0: slot 0

Security

DoS攻撃

いくつか対策方法がある。

サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。

攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。

バリデーションの実装

基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。

ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。

二重送信

submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。

  1. ボタン連打
  2. ブラウザーバック
  3. リロード (PRG)

項目ごとにすべき対策が異なる。

連打

基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。

似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。

$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});

停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。

Other

Access Denied! Your IP address is blacklisted because of malicious behavior in the past

Webサイトを開くと、[Access Denied! Your IP address is blacklisted because of malicious behavior in the past] のメッセージが表示されてアクセスできないことがあるらしい。

Spamhausというスパムデータのブラックリスト共有サービスがあり、Apache HTTP Serverのspamhaus moduleでこれを使っていて拒否している可能性がある模様。

spamhauに解除申請するとすぐに解除してくれて、反映に12時間くらいかかる模様。

Browser

Bookmarklet

AutoScroll

https://chatgpt.com/share/683d5e8b-1744-800b-9fc9-a2e5c05754ca

MacのChromeはマウスホイールの中ボタンクリックのオートスクロールに対応していない。

面倒なので、ブックマークレットで対応する。

/* AutoScroll */
javascript:(function(){
  if(window.autoScrollInterval){
    clearInterval(window.autoScrollInterval);
    window.autoScrollInterval = null;
    /* alert("⏹ 自動スクロール停止"); */
  } else {
    /* ここでスクロール速度を調整(1 = 遅い、10 = 速い)*/
    const speed = 1;
    window.autoScrollInterval = setInterval(() => {
      window.scrollBy(0, speed);
    /* この間隔も調整可能(ミリ秒) */
    }, 20);
    /* alert("▶ 自動スクロール開始"); */
  }
})();

クリックするたびに、自動スクロールのオン・オフが切り替わる。便利。

Chromium

Extension

Chromme系で愛用拡張機能を列挙する。

Profile

https://chatgpt.com/c/67aca944-1fcc-800b-973e-7bf3207b9b91

Webサイトのアカウントを切り替えたい場合、Webブラウザーのプロファイル機能で、アカウント情報を分離できる (Googleアカウントではなくて)。

これでA用、B用など用途ごとにプロファイルを作って、それでセッションやブックマークなどを分けられる。

devtool/開発者ツール

イベントリスナー

要素に設定されているイベントを調べよう - ゆずめも

[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。

イベント監視

How to find out which JavaScript events fired? - Stack Overflow

monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。

Network conditions

開発者ツールの[Network]タブを開いてリロードしても、[No internet]と表示されることがある。

これはオプション設定の問題。上のツールバーの[Disable cache]の右が[Offline] だとこうなる。これを[No throttling]にすると解決する。クリックミスだと思われる。

IE Edge

保存された情報

Edgeで「保存された情報」の表示を無効にする方法 - shikumika’s diary

【Edge】「保存された情報」を削除する方法の解説

全部非表示にできるが、個別には削除できない模様。

[edge://wallet/settings]-[個人情報]-[基本情報の保存と入力]=[オフ]

これで全部無効になる。

[保存されたデータ] ならShift-Deleteで選択肢を削除できた模様。

Safari

Windows Safari

一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。

開発者ツール

PCでスマホサイトを見る方法 – Safari編|東京渋谷のWeb制作会社・ホームページ制作会社|株式会社イー・バード

Safariの開発者ツールは癖がある。

[設定]-[詳細]-[☑️Webデベロッパ用の機能を表示]

[開発]-[レスポンシブデザインモードにする]

スーパーリロード

サポートへようこそ|メールのトラブルやホームページに関するお問い合わせ、 CMS操作方法など各種サポート情報をご案内しております。/各ブラウザでの強制リフレッシュ(スーパーリロード)

Shift-更新ボタン

Firefox

カメラ

https://chatgpt.com/share/680eaa72-118c-800b-b032-34842d9a6c18

Firefoxでカメラが機能しないことがある。確認すべき事項がいくつかある。

  1. Firefoxの設定でカメラを有効にする。アプリの再起動必要。
  2. Webブラウザーのアドレスバー左側でカメラを許可する。1ができていないとカメラの項目が表示されない。

Shared Host

Free

無料で使用可能な共用ホスティングサービスがある。

スタードメイン無料サーバー

ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。

無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~

jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。

  • ディスク容量 20GB
  • DB 1GB

ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。

CORESERVER

Coupon

A8.netで自己アフィリエイトがある。これを経由すると少しお得になる。契約初回のみ。更新はだめ。

リージョン

GMOデジロック:レンタルサーバー「コアサーバー」、西日本リージョンを新設し、リージョン選択サービスを開始 | GMOインターネットグループのプレスリリース

2018-01-31から西日本リージョンも選べるようになったらしい。適宜分散させるといいかもしれない。

Pay

以下が可能。

  • クレジットカード
  • Amazon Pay

Amazon Payが使えるからAmazon PayでOK。

料金プラン | レンタルサーバー CORESERVER(コアサーバー)

料金表を見る限り、12か月以上がお得。迷ったら12か月でいいと思う。確信やキャンペーンがあるなら24/36も。

更新を考えるのが面倒だから、36でいいかも。

メール

情報

ルールが特殊なので注意する。

ゴミ箱に振り分ける場合。

順1 で[./.Trash] を指定

順2

  • 条件:  [.*]
  • 処理:  ./、に振り分ける

条件部分には正規表現が使えるように見える。

破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。

カスタムフィルターにくせがある。

  • エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」
ポイント

https://chatgpt.com/c/680398be-247c-800b-911e-df207cb6c6a3

  • 日本語はBASE64でエンコードされているので、そのままだとヒットしない可能性が高い。BASE64でエンコードされたキーワードの指定が必要な可能性が高い。
  • 検索範囲=[全体] は全部にANDで入っていることを期待している感じがするので、Subjectに絞り込む。

1個目のBASE64が重要な気がする。これで様子を見る。

やっぱりうまくいかない。

Thunderbirdのメールフィルターで処理する。これが確実。サーバー側で対応していないから、外出先で適用されないのが欠点だが。

Value Domain ネットde診断 byGMO

2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。

CGI

CORESERVERでのCGIの設定方法がある。

CORESERVERのFastCGI版PHPとCGI版PHPの設定方法
項目 FastCGI CGI
バージョンの変更 管理画面 .htaccess内の

AddHandler application/x-httpd-phpcgiXX .php

設定ディレクトリー /virtual/<username>/public_html/.fast-cgi-bin/
CGIの実行ファイル phpXX.fcgi phpXX.cgi
PHPの設定ファイル phpXX.ini php.ini
設定の反映タイミング バージョン切替時 即時

~/public_html/.fast-cgi-bin/のphpXX.fcgi phpXX.cgiがCGIの実行ファイル。このファイルか最後の行のexecのパスを変更すると、自前コマンドに変更可能。

FastCGIは管理画面からバージョンを変更したタイミングで反映される。ただ、ファイル拡張子が.phpじゃないとこのFastCGIが実行されない模様。

CGIは.htaccessに以下の内容を記述してCGI板PHPのバージョンを指定する。

AddHandler application/x-httpd-phpcgiXX .php

cgiのファイルには実行権限が必要。

chmod +x py.py

拡張子がないとダメな模様。加えて、.htaccessに以下の記述。

AddHandler cgi-script .py

これでpy.pyで動作はする。

拡張子じゃなくてファイル名で実行したい場合、SetHandlerでしていする (AddType, AddHandler, SetHandlerの違い – senooken JP)。

<FilesMatch py$>
    SetHandler cgi-script
</FilesMatch>

これでpyでもアクセスできる。

FastCGI版の場合、以下のような設定でファイル名でマッチさせれば実行できそうな気もするが。

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

500

<FilesMatch gnusocial$>
        SetHandler application/x-httpd-php
</FilesMatch>

pythonがphpとして認識され、テキストがそのまま表示される。

SetHandler fcgid-scriptにしたらFastCGIで動作する。プログラムがFastCGI対応になっている必要がある。

<FilesMatch gnusocial$>
        SetHandler fcgid-script
</FilesMatch>

Function

サーバー間コピー

CORESERVERのサーバー間コピー | GNU social JP Web

巨大ファイル・大量ファイルを転送する場合、長時間プロセスになって、サーバーに強制終了される可能性がある。なので、scp/rsyncじゃなくて、レンタルサーバーのファイル転送機能を使う。

CORESERVERのサーバー間コピーは、リモート→ローカルの1方向のコピー。

coreserverのサーバー間コピーで発生したquotaの問題 - 渡米生活。(日記)」にあるように、ファイル数が多いとコピー漏れがあるので、事前にtarで1ファイルにまとめてからコピーすると検証しやすい。

  1. コントロールパネル-[サイト設定]-[サーバー間コピー]
  2. [サーバー間でのファイルコピー設定]-[サーバー間コピーの新規作成] で以下を入力して [サーバー間コピーを新規作成する]
    • サーバー間コピー名: コピーのタスク名
    • ローカル: 転送先の現在のサーバーのディレクトリー
    • 転送方式: 更新 (削除なし)。基本はこれで問題なく、他に [ミラー (削除なし)]、[差分 (削除なし)] を用途に応じて選択
    • リモート: 転送元のリモートサーバーの情報を入力。リモートディレクトリーはホームディレクトリーからの相対指定。

これでOK。以下の3点に特に注意する。

  1. リモート→ローカルの方向へのコピー。
  2. リモートディレクトリーはリモートディレクトリーの中身がコピーされる。指定したディレクトリー自体は転送されない。
  3. ローカルもリモートもディレクトリーはホームディレクトリーからの相対指定になるが、先頭に/が必要。

[サーバー間でのファイルコピー設定] 画面が表示されるので、作成した項目の [アクション] 列の [> (実行ボタン)] を選びます。

[サーバー間コピーの実行] の確認モーダルが表示されるので [サーバー間コピーを実行する] を選びます。

3分後ほどにコピーが始まります。タスクのログが [/.servercopy.log] に出力されます。

  • 転送先: senooken@m9.coreserver.jp
  • ローカルディレクトリ=/public_html/nc.senooken.jp (実体=/virtual/public_html/nc.senooken.jp)
  • リモート
    • FTPサーバー名=m9.coreserver.jp
    • FTPアカウント=
    • FTPパスワード
    • リモートディレクトリー=/public_html/tmp/ (実体=/virtual/public_html/tmp)

Analytics

Exam

## About

https://gnusocial.jp/notice/4506679

### 全般

- マーケティング・ビジネス実務検定

- IMA検定

- Web検定

- ネットマーケティング検定

### 解析系

- ウェブ解析士

- GAIQ

- 統計検定

- Webアナリスト検定

GAIQが無料だしどうせ使うからいいかな。

https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/

https://www.plan-b.co.jp/blog/seo/12792/

## URL

- https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/

- https://mynavi-creator.jp/blog/article/qualification-for-web-marketer

- https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html

- https://digitor.jp/textbook/web-analytical-qualification/

Tool

サイト分析用のツールがいくつかある (2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】)。

  • SimilarWeb
  • Ubersuggest
  • ahrefs
  • Googleキーワードプランナー

閲覧数取得

出典: GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN

  • [行動]-[サイトコンテンツ]-[全てのページ]
  • [表示する行数]=5000
  • [エクスポート]=TSV

流入元特定

会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。

こんにちは。

探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。

・自由形式レポートを作成

・セグメント作成 > ユーザーセグメント

・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定

・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存

・探索レポートにセグメントを適用

・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列

・指標:セッション

ご確認よろしくお願いいたします。

※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。

 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。

PMProでも似たような回答。

Google Analytics 4 can track ecommerce conversions and then assign page value to posts that were a part of their conversion path for that engaged session.

Server

httpd

Apache HTTP Server

About

httpdの利用可能な情報。

https://chatgpt.com/c/6761f851-df0c-800b-86e9-1624b458d66d

# 使用可能な指令一覧
apachectl -L
httpd -L

# 使用可能なモジュール一覧
apachectl -M
httpd -M

.htaccessで使用可能な指令の一覧。

.htaccessで使用可能な指令一覧 – senooken JP

Operation

サーバーの稼働や状態確認などで重要な操作がいくつかある。systemd前提。

ログ・状態確認。

sudo systemctl status apache2

sudoをつけないと詳細ログを確認できない。

sudo systemctl restart apache2
sudo systemctl start apache2
sudo systemctl stop apache2

Access Control

DoS攻撃対策などで重要な設定。

mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。

基本構文は以下。

Require host <address>
Require ip <ip address>

1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。

Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。

mod_cgi

mod_cgi - Apache HTTP Server Version 2.4

CGIプロトコルのApacheモジュール。cgi-scriptにハンドラーを割り当てるとCGIとして扱う。

mod_fcgid

mod_fcgid - Apache HTTP Server Version 2.5

FastCGIプロトコルのApacheモジュール。AddHandlerかSetHandlerでfcgid-scriptハンドラーに割り当てられると、FastCGIとして処理される。

プログラム側もFastCGIに対応している必要がある。

Error

sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/apache2.service.d
             └─privatetmp.conf
     Active: failed (Result: exit-code) since Fri 2024-12-06 15:09:28 JST; 12s ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 38461 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)

Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: [Fri Dec 06 15:09:28.259153 2024] [core:warn] [pid 38464] AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00112: Warning: DocumentRoot [/home/gree/frontend/greenet/htdocs_net] does not exist
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00526: Syntax error on line 7 of /etc/apache2/conf-available/rewrite-greenet.conf:
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: RewriteRule: unknown flag 'UnsafeAllow3F'
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: Action 'start' failed.
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: The Apache error log may have more information.
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Failed with result 'exit-code'.
Dec 06 15:09:28 z-ken-senoo systemd[1]: Failed to start The Apache HTTP Server.
AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8

NameVirtualHost指令が廃止予定なので、行を削除して対応する。

AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.

DefaultTypeはnone以外意味がなく、警告表示になる模様。

.htaccess

directive

.htaccessで使用可能な指令一覧 – senooken JP

.htaccessで使用不能なよく登場して誤解する指令を整理しておく。

  • Alias
  • ScriptAlias
  • Directory/DirectoryMatch
  • Location/LocationMatch

逆にOKなもの。

  • Files/FilesMatch

mod_rewrite

Apache mod_rewrite - Apache HTTP Server Version 2.4

https://grok.com/share/c2hhcmQtMw%3D%3D_051d98f7-939d-4c82-977d-c30f506b61c7

リダイレクトを扱うモジュール。非常によく使うので重要。

  • RewriteEngine: mod_rewriteの機能のON/OFF。基本は使う前にOnにするだけ。
  • RewriteBase: ベースURLを指定。サブディレクトリー以下で、相対パスでリダイレクトする際に使用。
  • RewriteCond: RewriteRuleの実行条件指定。
  • RewriteRule: 実際のURL変換ルール。
  • RewriteMap: 外部ファイルからマッピングを取得して変数に割り当てる。
  • RewriteOptions: mod_rewriteの動作オプション設定。
RewriteBase

ベースURLを指定。サブディレクトリー以下で、相対パスでリダイレクトする際に使用。記述の簡略化が可能。

# /blogディレクトリ内の.htaccessの場合
RewriteBase /blog/

RewriteRule ^archives/([0-9]+)$ archives/detail.php?id=$1 [L]
# 上記は /blog/archives/123 → /blog/archives/detail.php?id=123 になる
RewriteRule

mod_rewriteのコア。マッチしたパターンを置換先にリダイレクトする。

RewriteRule Pattern Substitution [flags]
Flags

RewriteRule Flags - Apache HTTP Server Version 2.4

指定可能なフラグが大量にある。が、よく使うものは少数。よく使う準。

  • L|last: これ以上ルールを処理しない。関数でいうreturn/exit/break相当。これを指定しない場合、上のほうのRewriteRuleで書き換えた結果を、後続のRewriteRuleで処理することになる。基本は1 RewriteRuleにつき1L。ほぼ常につける。
  • QSA|qsappend: Query String Append。本来、書き換えする際、?%{QUERY_STRING}を自分で明示的にしない限り、クエリー文字列は破棄される。破棄せずに自動的に引き継いでくれる。リダイレクトするときに、クエリー文字列も引き継いでほしいことが多いのでよく指定する。ほぼ常につける。
  • R=301: 外部リダイレクト。これを指定しない場合、内部リダイレクト (URLは変わらない)。
  • NC|nocase: Patternのマッチの大文字小文字を無視する。
  • B (escape backreferences): 変換前に非英数字をエスケープする。後方参照時に基本的に使う。URLのマッピング前に、URL内のエスケープを解除する。したがって、後方参照時に、エスケープが解除される。このフラグを適用すると、後方参照内の英数字以外がエスケープされる。例えば、検索フォームでx & y/zを入力すると、アドレスバーやリクエストはエスケープしてくれる。が、後方参照はエスケープを解除してしまうので、BがないとURLにx&y/zがそのまま登場して不正なURLになる。
  • PT|passthrogh: Alias/ScriptAlias/Redirectを解釈したい場合に使用。

L(100%) > QSA(90%) > R(70%) > NC(50%) > B(40%) > PT(20%)

あまり使わない。

  • UnsafeAllow3F: 基本は使わない。Apache v2.2までは、URLクエリー文字列内部に?がある場合、バックリファレンスで?がそのままだった。が、v2.4からはエンコードして%3Fにしている。この動きが困る場合だけつける。レガシー互換用。本来ならアプリで対応すべき内容。

[L,QSA] をデフォルトフラグに思っておくとよい。R/NC/B/PTは状況に応じて、状況にマッチしたら必須になる。

RewriteCond
RewriteCond TestString CondPattern [flags]

RewriteCondはルールの条件 (if文相当) の定義指令。RewriteRuleの直前に配置する。

RewriteRuleで使用可能な変数をテストしてRewriteRuleで書き換えるかどうか振り分ける。

# 1. ファイルが存在しない場合のみリライト
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L]

# 2. HTTPS接続を強制
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# 3. 特定のUser-Agentをブロック
RewriteCond %{HTTP_USER_AGENT} (malicious-bot|spammer) [NC]
RewriteRule .* - [F]

# 4. ホットリンク防止
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com/ [NC]
RewriteRule \.(jpg|png|gif)$ - [NC,F,L]
変数
HTTP headers: connection & request:
HTTP_ACCEPT

HTTP_COOKIE HTTP_FORWARDED HTTP_HOST HTTP_PROXY_CONNECTION HTTP_REFERER HTTP_USER_AGENT

AUTH_TYPE

CONN_REMOTE_ADDR CONTEXT_PREFIX CONTEXT_DOCUMENT_ROOT IPV6 PATH_INFO QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_PORT REMOTE_USER REQUEST_METHOD SCRIPT_FILENAME

server internals: date and time: specials:
DOCUMENT_ROOT

SCRIPT_GROUP SCRIPT_USER SERVER_ADDR SERVER_ADMIN SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE

TIME_YEAR

TIME_MON TIME_DAY TIME_HOUR TIME_MIN TIME_SEC TIME_WDAY TIME

API_VERSION

CONN_REMOTE_ADDR HTTPS IS_SUBREQ REMOTE_ADDR REQUEST_FILENAME REQUEST_SCHEME REQUEST_URI THE_REQUEST

特によく使うものは以下。

  • REQUEST_FILENAME: リクエストされたファイルのサーバー上の絶対パス。
  • REQUEST_URI: /index.htmlのようなリクエストURIのパス部分。URLクエリーはQUERY_STRINGにある。
CondPattern

CondPatternはTestStringに対する正規表現 (PCRE) が基本。ただし、いくつかの追加の構文が使用可能。

  1. !文字の前置でCondPatternの否定になる。
  2. 辞書比較演算子が使用可能。
    1. <
    2. >
    3. =
    4. <=
    5. >=
  3. 数値比較演算子が使用可能。
    1. -eq
    2. -ge
    3. -gt
    4. -le
    5. -lt
    6. -ne
  4. ファイル属性テスト。
    1. -d: ディレクトリー判定。
    2. -f: ファイル判定。
    3. -F: 内部リクエスト経由のファイル判定。サーバー性能に影響ある。
    4. -l/-h/-L: シンボリックリンクの判定。-lt/-leとの混同防止で-h/-Lも使用可能。
    5. -s: ファイル判定+0超過ファイル。
    6. -U
    7. -x: 実行権限
  5. TestStringが特殊値exprの場合、CondPatternはap_exprとみなす。

ファイル属性テストの-d/-fはよく使う。

Flags

RewriteCondの第3引数にフラグを指定できる。これは以下の3種だけ指定可能で、CondPatternに作用する。

  • nocase|NC (No Case): 大文字小文字の違いを無視。
  • ornext|OR (OR next condition): RewriteCondを複数記載時に、デフォルトのANDではなくORで判断する。
  • novary|NV (No Vary): 条件にHTTPヘッダーを使用した場合、このフラグはレスポンスのVaryヘッダーに使用ヘッダーの追加を抑制する。あまり使わない。

ORをよく使う。

Debug

RewriteRuleは条件が複雑になりがちで、デバッグが重要。いくつか方法がある。

Log Level alert rewrite:trace3

mod_rewriteはLogLevelでのログ用にtrace1-trace8 (debug-emergに対応?) までのログレベルを用意している。

trace8=debug未満では、何のログも出力しない。2超過は性能が落ちるのでデバッグ用にだけ使う。



auth

認証、承認、アクセス制御 - Apache HTTP サーバ バージョン 2.4

Apache HTTP Serverで実現可能な認証機能が複数ある。

mod_authn_core と mod_authz_core がコア機能。

mod_authz_core

アクセス制御の指令がいくつかある。Apache 2.2まで使用されていた、Allow/Deny/Order/Satisfyがあったのだけど、2.4でこれが整理されて、別の記法が推奨になった。

対応関係

対応関係を整理する。

昔の記法はシンプルだが、複数組み合わせた複雑な論理がしにくく、評価順序による予期せぬ動作が発生しやすかった。

新しい記法だと、認証プロバイダー (例: ip/host/user/group/all) で定義でき、<RequreAll> (初期値)のOR、<RequireAll> のAND、<RequreNone> NOTで複雑な組み合わせが可能になり、Satisfyも不要になった。

シナリオ 古い記法 (2.2以前) 新しい記法 (2.4以降) 説明
すべて許可 Order allow,denyAllow from all Require all granted 無条件でアクセスを許可。
すべて拒否 Order deny,allowDeny from all Require all denied 無条件でアクセスを拒否。
特定IPからのみ許可(他拒否) Order deny,allowDeny from allAllow from 192.168.1.1 Require ip 192.168.1.1 IPアドレス(またはサブネット: 192.168.1)を指定。部分一致可能。
特定ドメインからのみ許可(他拒否) Order deny,allowDeny from allAllow from example.com Require host example.com ホスト名やドメインを指定。サブドメインも対応(例: .example.com)。
すべて許可だが特定IPを拒否 Order allow,denyAllow from allDeny from 192.168.1.1 <RequireAll>Require all grantedRequire not ip 192.168.1.1</RequireAll> 否定には<RequireAll>を使い、AND論理で制限。複数拒否も追加可能。
認証とIP制限の両方が必要(AND) Order deny,allowDeny from allAllow from 192.168.1.1Satisfy allAuthType BasicAuthName "Secure"AuthBasicProvider fileAuthUserFile /path/to/usersRequire valid-user AuthType BasicAuthName "Secure"AuthBasicProvider fileAuthUserFile /path/to/users<RequireAll>Require valid-userRequire ip 192.168.1.1</RequireAll> Satisfy all<RequireAll>で置き換え。認証ディレクティブは共通。
認証かIP制限のどちらかでOK(OR) Order deny,allowDeny from allAllow from 192.168.1.1Satisfy anyAuthType BasicAuthName "Secure"AuthBasicProvider fileAuthUserFile /path/to/usersRequire valid-user AuthType BasicAuthName "Secure"AuthBasicProvider fileAuthUserFile /path/to/usersRequire valid-userRequire ip 192.168.1.1 デフォルトでOR論理(<RequireAny>相当)。明示的に<RequireAny>を使ってもOK。
グループ認証とIP拒否の組み合わせ Order allow,denyAllow from allDeny from bad.example.comAuthType BasicAuthName "Secure"AuthBasicProvider fileAuthUserFile /path/to/usersAuthGroupFile /path/to/groupsRequire group adminSatisfy all AuthType BasicAuthName "Secure"<br>AuthBasicProvider fileAuthUserFile /path/to/usersAuthGroupFile /path/to/groups<RequireAll>Require group adminRequire all grantedRequire not host bad.example.com</RequireAll> 複雑な論理はコンテナで表現。<RequireNone>で複数のNOTも可能(例: <RequireNone> Require host bad1 Require host bad2 </RequireNone>)。

デフォルトがORなので、<RequireAll>でAND条件にするのが基本。

特定IP/hostのみ除外はよく使うと思われる。

<RequireAll>
Require all granted
Require not ip 192.168.1.1
</RequireAll>
Require

httpd v2.4で刷新された認証指令。非常に重要。

Require [not] <entity-name> [<entity-name> ...] <argument>

上記のような書式。<entity-name> (プロバイダー) が複数あって、これで識別する。

  • Require all granted: 全員許可
  • Require all deniede: 全員禁止。
  • Require env <env-var> [<env-var> ...]: いずれかの環境変数がある場合許可。
  • Require method <http-method> [<http-method>...]: 指定したHTTPメソッドのみ許容。
  • Require expr <expression>: <expression> がtrueの場合許容。
  • Require user <userid> [<userid>...]: 指定したユーザーのみ。
  • Require group <group-name> [<group-name>...]: 指定したグループのみ。
  • Require valid-user: 有効なユーザーのみ (パスワードファイルに記載のあるユーザーのみ)
  • Require ip <ip> [<ip>...]: 指定したipのみ。ip/netmaskやip/CIDRの表記も可能。
  • Require host <host-name> [<host-name>...]: 指定ホストのみ。
  • Require forward-dns <>
  • Require local: ローカルのみ。
Basic

一番基本的な認証機能では、<Directory>指令か、.htaccessで定義する。

以下の流れで認証設定する。

  1. htpasswdでパスワードを作成
  2. <Directive>/.htaccessで保護対象パスを指定。
  3. 認証方式とパスワードファイルの指定
htpasswd

htpasswd - Manage user files for basic authentication - Apache HTTP Server Version 2.4

最初にパスワードファイルを作成する。認証プロバイダーによって作成方法が異なる。

Basic認証では、htpasswdコマンドで作る。httpd付属のパスワード作成ソフト。

htpasswd [option] <passwordfile> <username>
  • 引数
    • <passwordfile>: 作成するパスワードファイルのパス。
    • <username>: パスワードのユーザー名。
  • オプション
    • -c: create。パスワードファイルを新規作成する。上書きするので初回だけ実行すること。

例:

htpasswd -c /usr/local/apache/passwd/passwords rbowen

htpasswdを実行するとパスワードの入力が要請されるので、入力する。

ログイン前に確認されないように、パスワードファイルは、Webからアクセス不能な場所 (documentroot外部) に配置する。

.htaccess

パスワードファイルを作成したら、設定で参照する。

httpd.confの<Directory> セクションか、.htaccessで以下の内容を記載する。

AuthType Basic
AuthName "Restricted Files"
# (Following line optional)
AuthBasicProvider file
AuthUserFile /usr/local/apache/passwd/passwords
Require user rbowen

指令の内容は以下の通り。

  • AuthType: 認証方式。一般的なのはBasic。パスワードを暗号化せずにクライアントに送信するので、HTTPS必須。
  • AuthName: 認証に使うRealm (領域) を指定。2種類の役割がある。1. パスワード入力ダイアログに表示する情報の一部としてWebブラウザーが使う。2. 認証領域の流用で使う。同じRealmの指定があれば、クライアントに保存された同じパスワードをWebブラウザーが自動入力しようとする。
  • AuthBasicProvider: 認証プロバイダーの指定。初期値fileなのでAuthType Basicの場合省略可能尾。mod_authn_dbm/mod_authn_dbdなどDBを使う場合指定必須。
  • AuthUserFile: htpasswdで作成したパスワードファイルのパスを指定。リクエストのたびにこのプレーンテキストを検査する。ユーザー数が数百を超えると遅延を感じる。その場合、mod_authn_dbmのAuthDBMUserFileでDBファイルを指定したりする。
  • Require: アクセス可能なユーザーを指定する。

Requireはいくつか指定方法がある。ユーザーを指定する方式だと、複数ユーザーを追加する場合、都度修正が必要になる。

グループの指定か、valid-userで複数ユーザーを管理できる。

AuthGroupFileで以下のようなユーザー名を列挙したグループを定義する。

GroupName: rbowen dpitts sungo rshersey

続いて、htpasswdに上記のユーザーを追加する。

htpasswd /usr/local/apache/passwd/passwords dpitts

最後に、Require group GroupNameでグループを指定する。

AuthType Basic
AuthName "By Invitation Only"
# Optional line:
AuthBasicProvider file
AuthUserFile /usr/local/apache/passwd/passwords
AuthGroupFile /usr/local/apache/passwd/groups
Require group GroupName

これで複数ユーザーをグループファイルに外だしできる。

他に、Require valid-userを指定すると、パスワードファイル記載のどのユーザーでも承認する。

パスワードファイルがグループも兼ねるイメージ。ユーザーが少ないなら、Require valid-userがシンプル。

E-mail

[サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]

MailHog: Go言語製のメールサーバーソフト。

Debian

PHP8

[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](https://computingforgeeks.com/how-to-install-php-on-debian-linux/)

Debian 11の場合、PHP 8には外部リポジトリーが必要なので追加する。

sudo apt update

sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2

PHPパッケージを追加する。

echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list

wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add -

sudo apt update

これでPHP8を参照できるので、インストールする。

sudo apt install php8.2

[How to Switch between Multiple PHP Version on Debian 12/11/10 – TecAdmin](https://tecadmin.net/switch-between-multiple-php-version-on-debian/)

インストールしたら、PHPのバージョンを切り替える。

a2dismod php7.4

a2enmod php8.2

sudo systemctl restart apache2

php 8.2にするとこういうエラー。

[Sat Sep 02 11:31:02.558029 2023] [php:error] [pid 25644] [client 133.106.38.37:57181] PHP Fatal error:  Uncaught Error: Undefined constant "DB_DATAOBJECT_ERROR_NODATA" in /var/www/gnusocial/public/index.php:104\nStack trace:\n#0 [internal function]: handleError()\n#1 {main}\n  thrown in /var/www/gnusocial/public/index.php on line 104

念のためdockerで起動を試みましたが、同じくトップ画面を開くと同じエラーになります。

<https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。

私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?

alternative

Ref: DebianAlternatives - Debian Wiki.

OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。

sudo update-alternatives --display vi
sudo update-alternatives --config vi

オプションとコマンド名を指定することで、現在の実体と更新ができる。

XAMPP

ポート番号変更

Xamppでポート競合を防ぐ方法 #PHP - Qiita

XAMPP Control PanelのConfigから変更可能。

phpmyadminはConfigのphpmyadminで、Servers.portを追加する。