【入門編】Composerの「Custom Repositories」詳細解説:独自のパッケージサーバーを構築して社内ライブラリをセキュアに管理する – ビルド・パッケージ管理ツール生産性向上バイブル

こんにちは!開発現場を支えるインフラやツールの設計に日々向き合っている先輩エンジニアです。

PHPのプロジェクトを進めていく中で、こんな悩みを持ったことはありませんか?
「社内で共通して使う認証機能や、便利なAPIラッパーをライブラリ化したいけれど、毎回コピペするのは管理が地獄だ……」
「かといって、GitHubのプライベートリポジトリを毎回Composer経由で読み込ませようとすると、デプロイサーバーごとのSSH鍵の管理や権限設定で頭が痛くなる……」
「かといって、有償の Private Packagist を導入するほどの予算はまだ降りない……」

もしあなたがこの壁にぶつかっているなら、今回のテーマはまさに救世主になります。今回は、大げなパッケージサーバーを立てず、「静的なJSONファイルを配信するだけ」という超軽量かつ極めてセキュアな手法で、独自のComposerリポジトリを構築・運用する方法を徹底解説します。

これをマスターすれば、社内ライブラリの管理が劇的にスマートになり、毎日のデプロイやバージョン管理のストレスから完全に解放されますよ。さあ、一緒に扉を開けていきましょう!

—

1. そもそもComposerの「Custom Repositories」とは何か?

普段、私たちは `composer require monolog/monolog` のようにコマンドを実行すると、Packagist.org という世界中のオープンソースが集まる巨大な中央リポジトリからライブラリをダウンロードしていますよね。

しかし、Composerは非常に拡張性が高く設計されています。設定ファイル(`composer.json`)の `repositories` セクションを書き換えるだけで、「公式以外の独自の場所(サーバーやローカルディレクトリ)からパッケージを探してきなさい」と指示することができるのです。

なぜ「Satis」や「Private Packagist」を使わないのか?

Composer公式のパッケージビルダーである「Satis」や、有償の「Private Packagist」は非常に強力です。しかし、小規模なチームや社内ニッチなライブラリ群を管理するためだけに、専用のビルドプロセスをCI/CDに組み込んだり、常時稼働のミドルウェアを用意するのは、オーバーエンジニアリング(過剰品質)になりがちです。

今回紹介する「静的JSON配信方式」の本質は、「Webサーバーが置ける環境(Nginx, Apache, あるいはS3などのオブジェクトストレージ)に、たった1つの `packages.json` を置くだけ」という圧倒的なシンプルさにあります。データベースも不要、ビルドスクリプトも不要。だからこそ壊れにくく、メンテナンスフリーで運用できるのです。

—

2. アーキテクチャの全体像を理解する

まずは、この仕組みが裏側でどう動いているのか、データとリクエストの流れを把握しましょう。

1. 社内ライブラリ(Provider): 独自のロジックを持つPHPコード。通常のComposerパッケージとして作られており、Git等で管理されています。
2. リポジトリサーバー(Repository): パッケージのメタデータ(名前、バージョン、zipファイルの置き場所)を記述した `packages.json` を公開しているWebサーバー。
3. 利用側プロジェクト(Consumer): `composer.json` に独自リポジトリのURLを登録し、`composer require` を実行するアプリケーション。

利用側がインストールを要求すると、Composerはまず独自リポジトリの `packages.json` をフェッチし、「どのバージョンのzipをどこからダウンロードすべきか」を解決して、一気に取得・配置します。

—

3. 実践!最小限の独自リポジトリを構築するステップ

それでは、実際に手を動かして、ローカル環境(あるいは社内LAN上のサーバー)にこの仕組みを再現してみましょう。

今回は分かりやすくするために、以下の構成で進めます。

  • パッケージ名: `acme/logger-util` (社内用ログユーティリティ)
  • リポジトリ配信元: `https://repo.internal.net/packages.json`(今回は手元のPCでローカルサーバーを立ててシミュレート)

ステップ1: 社内ライブラリ側の準備

まず、社内ライブラリとなるPHPプロジェクトを作成し、独自の `composer.json` を用意します。

{
“name”: “acme/logger-util”,
“description”: “社内システム共通の軽量ロガー”,
“type”: “library”,
“license”: “proprietary”,
“authors”: [
{
“name”: “Dev Team”,
“email”: “dev@example.com”
}
],
“require”: {
“php”: “^8.1”,
“monolog/monolog”: “^3.0”
},
“autoload”: {
“psr-4”: {
“Acme\\LoggerUtil\\”: “src/”
}
}
}

  • 解説: ここで重要なのは `type: “library”` の指定と、一目で社内用とわかるベンダー名(`acme/`)です。このプロジェクト自体をタグ(例: `v1.0.0`)を切って管理し、最終的にzipアーカイブとして固めておきます(GitHubのreleases機能や、自前のファイルサーバーにアップロードします)。

—

ステップ2: 静的 `packages.json` の作成

次に、これが今回のキモとなるメタデータファイルです。適当なディレクトリ(例: `/var/www/repo/packages.json`)に以下のJSONを配置します。

{
“packages”: {
“acme/logger-util”: {
“1.0.0”: {
“name”: “acme/logger-util”,
“version”: “1.0.0”,
“description”: “社内システム共通の軽量ロガー”,
“type”: “library”,
“require”: {
“php”: “^8.1”,
“monolog/monolog”: “^3.0”
},
“autoload”: {
“psr-4”: {
“Acme\\LoggerUtil\\”: “src/”
}
},
“dist”: {
“url”: “https://repo.internal.net/archives/logger-util-1.0.0.zip”,
“type”: “zip”
}
}
}
}
}

  • 解説:
  • `”packages”` の下に、パッケージ名、バージョン、依存関係、そして実体ファイル(zip)のダウンロードURL(`dist.url`)を明示的に記述します。
  • これにより、ComposerはPackagistを見に行かなくても、「ここからこのバージョンをダウンロードすればいいんだな」と完璧に理解できます。

これをNginxやApacheなどのWebサーバーで公開し、`https://repo.internal.net/packages.json` でアクセスできるようにしておきます。

—

ステップ3: 利用側プロジェクト(Consumer)での設定

いよいよ、実際に開発しているアプリケーション(利用側)から、この独自リポジトリを呼び出してみましょう。

アプリケーション側の `composer.json` に、以下のように `repositories` を追加します。

{
“name”: “myapp/web”,
“type”: “project”,
“require”: {
“php”: “^8.1”
},
“repositories”: [
{
“type”: “composer”,
“url”: “https://repo.internal.net/packages.json”
}
]
}

  • 解説:
  • `type: “composer”` と指定することで、ComposerはこのURLがPackagist互換のJSON構造を持っていると認識します。
  • これにより、公式のPackagistに登録されていない社内専用パッケージを、通常と同じように扱えるようになります。

—

ステップ4: 動作確認(HelloWorld)

設定が完了したら、利用側のプロジェクトのルートディレクトリで、いよいよ魔法のコマンドを実行します。

composer require acme/logger-util:^1.0.0

【実行ログのイメージ】上のコマンドを叩いた際の内部挙動

Using version ^1.0.0 for acme/logger-util
./composer.json has been updated
Running composer update acme/logger-util
Loading composer repositories with package information
[200] https://repo.internal.net/packages.json <-- 独自サーバーからメタデータを取得! Updating dependencies Locking dependencies (including require-dev)

  • Installing acme/logger-util (1.0.0): Extracting archive <-- 指定したzipから抽出!

Writing lock file
Generating autoload files

おめでとうございます!これで、外部のパブリックなサーバーに一切依存することなく、完全に社内インフラのネットワーク内(あるいはBasic認証やIP制限をかけた安全な領域)だけで、プライベートなパッケージの解決とインストールが成功しました。

—

4. 実務で絶対に押さえておきたいセキュリティと運用の知見

「静的JSONを置くだけ」と聞くと、セキュリティ的に不安になる方もいるかもしれません。プロのアーキテクトとして、現場で運用する際に必ず考慮すべきポイントをいくつか授けておきます。

1. アクセス制御(認証)の掛け方

社内ライブラリが完全にオープンであっては困る場合(ビジネス上の機密ロジックなど)、リポジトリサーバー(`https://repo.internal.net/`)に対してアクセス制限をかけます。

  • IP制限: 社内VPNや特定のCI/CDサーバーのIP以外からのアクセスを弾く。
  • HTTP Basic認証 / Bearerトークン: Composerは、リポジトリへの認証情報を設定する機能を持っています。

ComposerにHTTP認証情報をあらかじめ登録しておくコマンド
composer config –global http-basic.repo.internal.net ユーザー名 パスワード

この設定をしておけば、Composerは内部でリクエストを投げる際に自動的に認証ヘッダーを付与してくれます。CI/CD環境(GitHub ActionsやGitLab CIなど)でも、環境変数からこのコマンドをビルド前に実行するように仕込んでおけばスムーズです。

2. パッケージの更新(バージョニング)の自動化

毎回手動で `packages.json` を書き換えてzipをアップロードするのは、最初は良くてもヒューマンエラーの元になります。
小規模であっても、Gitのタグプッシュ(例: `git tag v1.1.0`)をトリガーにして、
1. ソースコードのzip化
2. サーバーへのアップロード
3. `packages.json` のバージョン情報の自動追記
を行う簡単なシェルスクリプトやGitHub Actionsワークフローを1つ書いておくだけで、開発体験はまるで「自前SaaS」のような快適さに進化します。

—

まとめ

今回は、Composerの「Custom Repositories」を活用し、SatisやPrivate Packagistを使わずに静的JSONファイルを配信するという超軽量かつセキュアな社内ライブラリ管理手法を解説しました。

  • 複雑なミドルウェアや有償ツールに頼らず、「静的JSONファイル」と「zip置き場」だけで構築できる
  • `composer.json` の `repositories` にURLを書き足すだけで、公式ライブラリと同じようにシームレスに扱える
  • Basic認証やIP制限を組み合わせることで、企業秘密を含むライブラリも安全にバージョン管理・配布できる

この手法を導入すれば、チーム内のコード共有が劇的にスムーズになり、コピペコーディングやバージョン不整合のトラブルとはもうお別れです。ぜひ、次のプロジェクトの基盤設計に取り入れてみてください。あなたの毎日の開発が、より快適でクリエイティブなものになることを心から応援しています!

タイトルとURLをコピーしました