1<!-- 2 tagline: Host your own composer repository 3--> 4 5# Handling private packages with Satis or Toran Proxy 6 7# Toran Proxy 8 9[Toran Proxy](https://toranproxy.com/) is a commercial alternative to Satis 10offering professional support as well as a web UI to manage everything and a 11better integration with Composer. It also provides proxying/mirroring for git 12repos and package zip files which makes installs faster and independent from 13third party systems. 14 15Toran's revenue is also used to pay for Composer and Packagist development and 16hosting so using it is a good way to support open source financially. You can 17find more information about how to set it up and use it on the [Toran Proxy](https://toranproxy.com/) website. 18 19# Satis 20 21Satis on the other hand is open source but only a static `composer` 22repository generator. It is a bit like an ultra-lightweight, static file-based 23version of packagist and can be used to host the metadata of your company's 24private packages, or your own. You can get it from [GitHub](https://github.com/composer/satis) 25or install via CLI: 26`php composer.phar create-project composer/satis --stability=dev --keep-vcs`. 27 28## Setup 29 30For example let's assume you have a few packages you want to reuse across your 31company but don't really want to open-source. You would first define a Satis 32configuration: a json file with an arbitrary name that lists your curated 33[repositories](../05-repositories.md). 34 35Here is an example configuration, you see that it holds a few VCS repositories, 36but those could be any types of [repositories](../05-repositories.md). Then it 37uses `"require-all": true` which selects all versions of all packages in the 38repositories you defined. 39 40The default file Satis looks for is `satis.json` in the root of the repository. 41 42```json 43{ 44 "name": "My Repository", 45 "homepage": "http://packages.example.org", 46 "repositories": [ 47 { "type": "vcs", "url": "https://github.com/mycompany/privaterepo" }, 48 { "type": "vcs", "url": "http://svn.example.org/private/repo" }, 49 { "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" } 50 ], 51 "require-all": true 52} 53``` 54 55If you want to cherry pick which packages you want, you can list all the packages 56you want to have in your satis repository inside the classic composer `require` key, 57using a `"*"` constraint to make sure all versions are selected, or another 58constraint if you want really specific versions. 59 60```json 61{ 62 "repositories": [ 63 { "type": "vcs", "url": "https://github.com/mycompany/privaterepo" }, 64 { "type": "vcs", "url": "http://svn.example.org/private/repo" }, 65 { "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" } 66 ], 67 "require": { 68 "company/package": "*", 69 "company/package2": "*", 70 "company/package3": "2.0.0" 71 } 72} 73``` 74 75Once you've done this, you just run `php bin/satis build <configuration file> <build dir>`. 76For example `php bin/satis build satis.json web/` would read the `satis.json` 77file and build a static repository inside the `web/` directory. 78 79When you ironed out that process, what you would typically do is run this 80command as a cron job on a server. It would then update all your package info 81much like Packagist does. 82 83Note that if your private packages are hosted on GitHub, your server should have 84an ssh key that gives it access to those packages, and then you should add 85the `--no-interaction` (or `-n`) flag to the command to make sure it falls back 86to ssh key authentication instead of prompting for a password. This is also a 87good trick for continuous integration servers. 88 89Set up a virtual-host that points to that `web/` directory, let's say it is 90`packages.example.org`. Alternatively, with PHP >= 5.4.0, you can use the built-in 91CLI server `php -S localhost:port -t satis-output-dir/` for a temporary solution. 92 93### Partial Updates 94 95You can tell Satis to selectively update only particular packages or process only 96a repository with a given URL. This cuts down the time it takes to rebuild the 97`package.json` file and is helpful if you use (custom) webhooks to trigger rebuilds 98whenever code is pushed into one of your repositories. 99 100To rebuild only particular packages, pass the package names on the command line like 101so: 102``` 103php bin/satis build satis.json web/ this/package that/other-package 104``` 105 106Note that 107this will still need to pull and scan all of your VCS repositories because any VCS 108repository might contain (on any branch) one of the selected packages. 109 110If you want to scan only a single repository and update all packages found in it, 111pass the VCS repository URL as an optional argument: 112``` 113php bin/satis build --repository-url https://only.my/repo.git satis.json web/ 114``` 115 116## Usage 117 118In your projects all you need to add now is your own composer repository using 119the `packages.example.org` as URL, then you can require your private packages and 120everything should work smoothly. You don't need to copy all your repositories 121in every project anymore. Only that one unique repository that will update 122itself. 123 124```json 125{ 126 "repositories": [ { "type": "composer", "url": "http://packages.example.org/" } ], 127 "require": { 128 "company/package": "1.2.0", 129 "company/package2": "1.5.2", 130 "company/package3": "dev-master" 131 } 132} 133``` 134 135### Security 136 137To secure your private repository you can host it over SSH or SSL using a client 138certificate. In your project you can use the `options` parameter to specify the 139connection options for the server. 140 141Example using a custom repository using SSH (requires the SSH2 PECL extension): 142 143```json 144{ 145 "repositories": [ 146 { 147 "type": "composer", 148 "url": "ssh2.sftp://example.org", 149 "options": { 150 "ssh2": { 151 "username": "composer", 152 "pubkey_file": "/home/composer/.ssh/id_rsa.pub", 153 "privkey_file": "/home/composer/.ssh/id_rsa" 154 } 155 } 156 } 157 ] 158} 159``` 160 161> **Tip:** See [ssh2 context options](https://www.php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-options) for more information. 162 163Example using HTTP over SSL using a client certificate: 164 165```json 166{ 167 "repositories": [ 168 { 169 "type": "composer", 170 "url": "https://example.org", 171 "options": { 172 "ssl": { 173 "local_cert": "/home/composer/.ssl/composer.pem" 174 } 175 } 176 } 177 ] 178} 179``` 180 181> **Tip:** See [ssl context options](https://www.php.net/manual/en/context.ssl.php) for more information. 182 183Example using a custom HTTP Header field for token authentication: 184 185```json 186{ 187 "repositories": [ 188 { 189 "type": "composer", 190 "url": "https://example.org", 191 "options": { 192 "http": { 193 "header": [ 194 "API-TOKEN: YOUR-API-TOKEN" 195 ] 196 } 197 } 198 } 199 ] 200} 201``` 202 203### Authentication 204 205When your private repositories are password protected, you can store the authentication details permanently. 206The first time Composer needs to authenticate against some domain it will prompt you for a username/password 207and then you will be asked whether you want to store it. 208 209The storage can be done either globally in the `COMPOSER_HOME/auth.json` file (`COMPOSER_HOME` defaults to 210`~/.composer` or `%APPDATA%/Composer` on Windows) or also in the project directory directly sitting besides your 211composer.json. 212 213You can also configure these by hand using the config command if you need to configure a production machine 214to be able to run non-interactive installs. For example to enter credentials for example.org one could type: 215 216 composer config http-basic.example.org username password 217 218That will store it in the current directory's auth.json, but if you want it available globally you can use the 219`--global` (`-g`) flag. 220 221### Downloads 222 223When GitHub or BitBucket repositories are mirrored on your local satis, the build process will include 224the location of the downloads these platforms make available. This means that the repository and your setup depend 225on the availability of these services. 226 227At the same time, this implies that all code which is hosted somewhere else (on another service or for example in 228Subversion) will not have downloads available and thus installations usually take a lot longer. 229 230To enable your satis installation to create downloads for all (Git, Mercurial and Subversion) your packages, add the 231following to your `satis.json`: 232 233```json 234{ 235 "archive": { 236 "directory": "dist", 237 "format": "tar", 238 "prefix-url": "https://amazing.cdn.example.org", 239 "skip-dev": true 240 } 241} 242``` 243 244#### Options explained 245 246 * `directory`: required, the location of the dist files (inside the `output-dir`) 247 * `format`: optional, `zip` (default) or `tar` 248 * `prefix-url`: optional, location of the downloads, homepage (from `satis.json`) followed by `directory` by default 249 * `skip-dev`: optional, `false` by default, when enabled (`true`) satis will not create downloads for branches 250 * `absolute-directory`: optional, a _local_ directory where the dist files are dumped instead of `output-dir`/`directory` 251 * `whitelist`: optional, if set as a list of package names, satis will only dump the dist files of these packages 252 * `blacklist`: optional, if set as a list of package names, satis will not dump the dist files of these packages 253 * `checksum`: optional, `true` by default, when disabled (`false`) satis will not provide the sha1 checksum for the dist files 254 255Once enabled, all downloads (include those from GitHub and BitBucket) will be replaced with a _local_ version. 256 257#### prefix-url 258 259Prefixing the URL with another host is especially helpful if the downloads end up in a private Amazon S3 260bucket or on a CDN host. A CDN would drastically improve download times and therefore package installation. 261 262Example: A `prefix-url` of `https://my-bucket.s3.amazonaws.com` (and `directory` set to `dist`) creates download URLs 263which look like the following: `https://my-bucket.s3.amazonaws.com/dist/vendor-package-version-ref.zip`. 264 265### Web outputs 266 267 * `output-html`: optional, `true` by default, when disabled (`false`) satis will not generate the `output-dir`/index.html page. 268 * `twig-template`: optional, a path to a personalized [Twig](http://twig.sensiolabs.org/) template for the `output-dir`/index.html page. 269 270### Abandoned packages 271 272To enable your satis installation to indicate that some packages are abandoned, add the following to your `satis.json`: 273 274```json 275{ 276 "abandoned": { 277 "company/package": true, 278 "company/package2": "company/newpackage" 279 } 280} 281``` 282 283The `true` value indicates that the package is truly abandoned while the `"company/newpackage"` value specifies that the package is replaced by 284the `company/newpackage` package. 285 286Note that all packages set as abandoned in their own `composer.json` file will be marked abandoned as well. 287 288### Resolving dependencies 289 290It is possible to make satis automatically resolve and add all dependencies for your projects. This can be used 291with the Downloads functionality to have a complete local mirror of packages. Just add the following 292to your `satis.json`: 293 294```json 295{ 296 "require-dependencies": true, 297 "require-dev-dependencies": true 298} 299``` 300 301When searching for packages, satis will attempt to resolve all the required packages from the listed repositories. 302Therefore, if you are requiring a package from Packagist, you will need to define it in your `satis.json`. 303 304Dev dependencies are packaged only if the `require-dev-dependencies` parameter is set to true. 305 306### Other options 307 308 * `output-dir`: optional, defines where to output the repository files 309 if not provided as an argument when calling the `build` command. 310 * `config`: optional, lets you define all config options from composer, except `archive-format` and `archive-dir` as the configuration is done through [archive](#downloads) instead. See 311 (http://getcomposer.org/doc/04-schema.md#config) 312 * `notify-batch`: optional, specify a URL that will be called every time a user installs a package. See (https://getcomposer.org/doc/05-repositories.md#notify-batch) 313