
August 13, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Managing proprietary code across multiple projects requires a reliable method for distributing internal libraries without exposing them to the public Packagist registry. Setting up PHP Composer private packages via Satis and Repman solves this by creating a self-hosted metadata repository that authenticates developers and serves zip archives directly from your infrastructure. Whether you are building legal-tech portals or multi-tenant eCommerce systems, this approach keeps intellectual property secure while maintaining standard Composer workflows.
For teams working on sensitive applications, such as those described in my Laravel development services, relying on public registries is not an option. You need full control over who can access specific versions of your internal SDKs, shared components, or domain-specific logic. The following sections break down exactly how to architect, deploy, and maintain these systems in production environments using current 2026 tooling.
How do you configure Satis for PHP Composer private packages?
Satis is the original open-source tool for generating static Composer repositories. It scans your configured Git repositories, reads their composer.json files, and generates a packages.json index along with individual package metadata files. Because the output is purely static HTML and JSON, it can be served by Nginx or Apache with minimal overhead, making it ideal for high-read, low-write environments where security and simplicity are paramount.
Creating the satis.json configuration
Your satis.json file defines which repositories to scan and how to output the metadata. For a typical legal-tech or eCommerce project sharing internal libraries, you will list each private Git URL explicitly. Avoid using wildcards in production; explicit lists prevent accidental inclusion of test repositories.
{
"name": "My Organization Private Repo",
"homepage": "https://packages.example.com",
"repositories": [
{ "type": "vcs", "url": "git@gitlab.example.com:internal/auth-sdk.git" },
{ "type": "vcs", "url": "git@gitlab.example.com:shared/legal-utils.git" }
],
"require-all": true,
"archive": {
"directory": "dist",
"format": "zip",
"prefix-url": "https://packages.example.com"
},
"config": {
"secure-http": true
}
} The archive section is critical. Without it, Composer clones the entire Git repository for every install, which is slow and exposes your full Git history to every developer machine. Enabling archives tells Satis to create zip snapshots of each tagged release, allowing Composer to download only the necessary source code via HTTP.
Automating builds with cron or CI
Satis does not run as a daemon. You must trigger rebuilds when code changes. In my experience managing deployments for sister sites like notarykathmandu.com and translationnepal.com, tying the Satis build to your CI pipeline ensures metadata stays synchronized with releases. Alternatively, a simple cron job running every five minutes works for smaller teams.
# Run Satis build every 5 minutes
*/5 * * * * www-data /usr/bin/php /var/www/satis/bin/satis build /var/www/satis/satis.json /var/www/html/public --no-interaction 2>&1 | logger -t satis-build Ensure the user running the build (often www-data or a dedicated satis user) has SSH keys configured with read-only access to your private Git repositories. Permission errors here are the most common cause of silent failures in PHP Composer private packages via Satis and Repman setups.
What advantages does Repman offer over Satis for private registries?
While Satis handles metadata generation excellently, it lacks user management, a web interface, and proxy caching. Repman (Repository Manager) fills these gaps by providing a full-featured application layer on top of Composer distribution. For agencies or product teams managing multiple client projects with different access levels, Repman reduces operational friction significantly.
| Feature | Satis | Repman |
|---|---|---|
| Metadata Generation | Static JSON (Fast) | Dynamic + Cached |
| User Authentication | Web Server Level (Basic/Auth) | Built-in Token/OAuth/LDAP |
| Proxy/Caching | No | Yes (Packagist Mirror) |
| Web UI | Simple List | Full Dashboard |
| Organization/Team Mgmt | No | Yes |
| Setup Complexity | Low | Medium (Docker/PHP App) |
| Best For | Single-team, Read-heavy | Multi-team, Agency, Enterprise |
Repman’s proxy feature is particularly valuable in regions with inconsistent internet connectivity, a reality I frequently navigate when deploying infrastructure in Nepal. By caching public Packagist packages locally, Repman ensures that composer install succeeds even if the upstream registry is slow or blocked, while still enforcing authentication for your private packages.
How do you authenticate Composer against a private repository?
Authentication is where most implementations fail. Composer needs credentials to fetch both the metadata index and the actual zip archives. For PHP Composer private packages via Satis and Repman, you should avoid embedding passwords in composer.json. Instead, use token-based authentication stored in the global auth.json or environment variables.
Configuring auth.json for CI and developers
When using Repman, each user or CI runner receives a unique API token. This allows granular revocation without rotating shared secrets. Add the repository and token to your project’s auth.json (never commit this file) or the global ~/.composer/auth.json.
{
"bearer": {
"packages.example.com": "repman-token-xxxxxxxxxxxx"
}
} For Satis without Repman, authentication typically happens at the web server level using HTTP Basic Auth. In this case, store credentials under the http-basic key. If you are integrating this into a broader deployment workflow, consider reading my guide on CI/CD pipeline setup for patterns on injecting these secrets securely during automated builds.
Handling archive authentication
A frequent pitfall is securing the metadata but leaving the /dist directory open. Since Satis generates static zip files, your Nginx or Apache configuration must enforce the same authentication rules on the archive path. If using Repman, this is handled automatically by the application router. For pure Satis, ensure your web server config protects the entire document root, not just packages.json.
What are the best practices for maintaining private Composer repositories in 2026?
Running a private registry is an ongoing operational responsibility. Neglecting maintenance leads to stale metadata, broken deploys, and security vulnerabilities. Based on years of maintaining production PHP systems, these practices prevent common failures.
- Enforce HTTPS Everywhere: Composer 2.x refuses to connect to non-HTTPS repositories by default. Ensure valid TLS certificates via Let’s Encrypt. Self-signed certificates cause intermittent failures in CI environments that are difficult to debug.
- Tag Releases Religiously: Both Satis and Repman rely on Git tags to generate stable package versions. Branch-based installs (
dev-main) are slower and less predictable. Enforce tagging policies in your team’s workflow, especially for shared libraries used across multiple client projects. - Monitor Disk Space: Archive directories grow indefinitely. Implement a cleanup strategy that retains only the last N versions of each package. For Repman, configure retention policies in the admin panel. For Satis, add a post-build script to prune old zips.
- Separate Metadata from Source: Never serve your private registry from the same server hosting your Git repositories. Compromise of the registry should not grant access to source code history. Use object storage (S3/MinIO) for archives when possible.
- Test Restores Quarterly: Verify that a fresh
composer installworks with only the credentials and repository URL. Documentation rot is real; automated smoke tests catch configuration drift before it blocks production deployments.
How do you troubleshoot common Composer private repository failures?
Even well-configured systems break. When composer update fails against your private registry, systematic diagnosis saves hours. These are the issues I encounter most frequently when auditing client infrastructure or supporting teams adopting PHP Composer private packages via Satis and Repman.
Version resolution conflicts
If Composer reports that a package "could not be found in any version," verify that the tag exists and follows semantic versioning. Satis ignores malformed tags. Check the generated p/vendor/package.json file directly on the server to confirm the version appears. If missing, manually trigger a rebuild and inspect the build logs for Git fetch errors.
Authentication loops and 401 errors
A 401 error during archive download usually means the web server protecting /dist has different credentials than the metadata endpoint. Ensure both paths share the same auth configuration. For Repman, regenerate the API token; tokens can expire or be revoked. Clear Composer’s cache (composer clear-cache) to remove cached 401 responses.
SSL certificate verification failures
In local development environments or misconfigured CI runners, you may see SSL certificate problem: unable to get local issuer certificate. Never disable SSL verification in production. Instead, update the system CA bundle or specify the correct certificate path in COMPOSER_CAFILE. This is especially relevant when using internal CAs for corporate registries.
Stale metadata after new releases
If a new tag isn’t appearing, check the cron schedule or CI trigger. For Satis, verify the build user still has SSH access to the repository. For Repman, check the webhook configuration; missed webhooks mean delayed updates until the next scheduled sync. Monitoring build success rates prevents silent staleness.
Implementing Secure PHP Composer Private Packages via Satis and Repman
Establishing a self-hosted Composer registry is a foundational step for any organization serious about code reuse and security. Whether you choose the simplicity of Satis or the feature richness of Repman, the key is treating the registry as production infrastructure with proper monitoring, backups, and access controls. For teams in Nepal or globally, this eliminates dependency on external services while keeping proprietary logic contained. If you need assistance architecting secure package distribution for your Laravel or Symfony applications, contact me to discuss your specific requirements.

