- Cross-border pull timeouts: long TLS and small dist files multiply round trips until jobs hit GitLab job timeouts.
- Authentication gaps: private GitLab Package Registry tokens leak into logs or never reach
COMPOSER_AUTH, so installs fail late. - Lock file drift: developers resolve against one mirror while CI hits another, breaking checksums and
content-hashvalidation.
Scenarios & bottlenecks
Network stalls surface as hung composer install. Auth breaks on hostname mismatches for self-managed GitLab. Locks break when mirrors rewrite dist URLs or composer.lock is not committed.
On shared Apple Silicon, disk queue depth rivals bandwidth. Pair this with Git, npm, and Homebrew CI optimization when agents also pull JS stacks.
Packagist, regional mirror, and enterprise chain (composer config)
Put private first, then an approved mirror, then repo.packagist.org. Swap URLs per compliance.
| Layer | Typical role | Example command |
|---|---|---|
| GitLab Package Registry | First-party PHP packages and forks | composer config repositories.gitlab composer https://gitlab.example.com/api/v4/group/123/-/packages/composer/ |
| Regional mirror | Lower latency for OSS when legal and security reviews pass | composer config repositories.aliyun composer https://mirrors.aliyun.com/composer/ |
| Enterprise Sonatype / Artifactory | Central proxy with audit trails | composer config repositories.corp composer https://nexus.example.com/repository/packagist-proxy/ |
| Official Packagist | Fallback for packages not mirrored | composer config --global repos.packagist composer https://repo.packagist.org |
Remove stale entries with composer config repositories.<name> --unset. Commit repositories in composer.json so Mac agents match CI.
GitLab CI: concurrency, HTTP proxy, and retry backoff
| Parameter | Suggested starting value | Notes |
|---|---|---|
COMPOSER_MAX_PARALLEL_HTTP |
6 shared Mac; 4 if SSD latency spikes | Caps dist downloads; smooths IO on shared hosts |
COMPOSER_PROCESS_TIMEOUT |
1200 seconds for large graphs | Match GitLab timeout; raise after mirrors are healthy |
HTTP_PROXY / HTTPS_PROXY |
Corporate gateway URL | Set NO_PROXY for internal GitLab and registries |
| Pipeline parallelism | resource_group: composer-pool or stagger schedules |
Stops many jobs hitting one mirror at once |
| Shell retry | 2s, 4s, 8s exponential sleep | Retry composer install --no-interaction --prefer-dist three times |
Example retry wrapper:
for i in 1 2 3; do
composer install --no-interaction --prefer-dist && break
sleep $((2 ** i))
done
Remote Mac cache directory, COMPOSER_CACHE_DIR, and CI cache keys
Set COMPOSER_CACHE_DIR on local SSD, e.g. /usr/local/ci/composer, not a network home. One cache per runner user helps hit rate when policy allows.
GitLab cache: example: key: ${CI_COMMIT_REF_SLUG}-php${PHP_VERSION}-files-composer.lock. Lock changes then invalidate cleanly.
Most teams avoid caching vendor/ long-term; cache metadata and dists instead.
Five-step rollout checklist
.tool-versions, or CI image to production.repositories in composer.json.COMPOSER_AUTH JSON before any Composer command runs.COMPOSER_CACHE_DIR in the job environment and add GitLab cache rules for lock-based keys.composer.lock is missing or stale; optional composer validate --strict.Facts you can paste into design docs
Six parallel HTTP requests is a practical default on shared remote Mac pools in 2026.
composer.lock is the CI contract; mirror changes without a fresh lock often cause checksum errors.
NO_PROXY for internal GitLab fixes many corporate proxy hangs.
FAQ
Why does Composer return HTTP 401 against my GitLab Package Registry? Bad or expired token, wrong scope, or host missing from gitlab-domains. Use deploy token or CI_JOB_TOKEN and the same COMPOSER_AUTH locally.
How should I handle Packagist or mirror rate limits in GitLab CI? Lower COMPOSER_MAX_PARALLEL_HTTP, stagger jobs, use enterprise mirrors with IP allow lists, cache when locks are stable.
What does content-hash or checksum failure mean after a mirror switch? composer.lock pins dist checksums. Different mirror payloads fail validation. Run composer update on a clean branch or align mirrors.
Summary
Put GitLab and enterprise before Packagist, commit composer.lock, cap parallel HTTP, set COMPOSER_CACHE_DIR on NVMe, and retry installs. The right remote Mac region shortens PHP CI queues.
No-login next steps: homepage, pricing, purchase, help center, technical blog.
Treat Composer mirrors like a traffic stack: always authenticate first, cache on fast disk, and never outrun your lock file, mirror policy, or approvals.