Local Composer for Everyone! A Conference-Friendly Satis Setup

Share this article

Local Composer for Everyone! A Conference-Friendly Satis Setup

While preparing my technical materials for WebSummerCamp, I realized my workshop would rely on a fairly stable internet connection, as we’d have a lot of ground to cover and a lot of packages to install. Rather than rely on the gods of live demos, or pre-installing everything and ruining the experience, I picked another route.

In this post, I’ll show you how to set up a local Satis instance and have it host the packages over the network it’s currently on, so that everyone who’s also connected to it can put the address into composer.json as a custom repository source, and retrieve all packages from your machine locally – no internet connection required!

Composer logo with deal with it sunglasses


Due to a habit of never installing programming-related software on my main OS (more about that here), I’m using Homestead Improved, as usual. If you have a working PHP installation on your host machine, or prefer Docker or something similar, please feel free to use that. Note, however, that for the sake of cross-platform friendliness and simplicity, this tutorial will be Homestead Improved-specific.

Before booting up the VM, make sure you share an arbitrary port. This can be done by editing the bottom section of Homestead.yaml. I picked 6789, so that my local “packagist” will be hosted on IP:6789 where IP will be the IP address of my host machine.


Inside the VM, in an arbitrary location of your choice (I picked /home/vagrant/Code/) install a new Satis project with:

composer create-project composer/satis --stability=dev --keep-vcs

This will create the subfolder satis.

How Satis Works

Satis accepts a satis.json file which tells it which repositories to download, which versions of those repos to download, where to place them after the download, and more. For a more comprehensive overview of all options you can use in satis.json, see the docs.

Let’s create satis.json in the Code/satis folder created earlier. Then, inside satis.json, we place the packages we need. For example:

    "name": "NoFW Websc",
    "homepage": "http://nofw.websc:6789",
    "repositories": [
        { "type": "vcs", "url": "https://github.com/twigphp/Twig" },
        { "type": "vcs", "url": "https://github.com/sitepoint/Rauth" },
        { "type": "vcs", "url": "https://github.com/PHP-DI/PHP-DI" },
        { "type": "vcs", "url": "https://github.com/nikic/FastRoute" },
        { "type": "vcs", "url": "https://github.com/guzzle/guzzle" },
        { "type": "vcs", "url": "https://github.com/Respect/Validation" },
        { "type": "vcs", "url": "https://github.com/doctrine/annotations" },
        { "type": "vcs", "url": "https://github.com/thephpleague/glide" },
        { "type": "vcs", "url": "https://github.com/tamtamchik/simple-flash" },
        { "type": "vcs", "url": "https://github.com/Seldaek/monolog" },
        { "type": "vcs", "url": "https://github.com/cakephp/orm" },
        { "type": "vcs", "url": "https://github.com/Bee-Lab/bowerphp" },
        { "type": "vcs", "url": "https://github.com/markstory/mini-asset" },
        { "type": "vcs", "url": "https://github.com/natxet/CssMin" },
        { "type": "vcs", "url": "https://github.com/linkorb/jsmin-php" },
        { "type": "vcs", "url": "https://github.com/consolidation-org/Robo" },
        { "type": "vcs", "url": "https://github.com/symfony/var-dumper" },
        { "type": "vcs", "url": "https://github.com/consolidation-org/Robo" },
        { "type": "vcs", "url": "https://github.com/twigphp/Twig-extensions" }
    "require-all": true,
    "require-dependencies": true,
    "require-dev-dependencies": true,
    "archive": {
        "directory": "dist"

As you can see, the list is non-trivial. Depending on the conference connection, downloading all this in a room of 50 people would indeed be overly optimistic, especially considering mine is only one of three simultaneous workshops on the same internet connection, not counting the hotel guests. Keep in mind that in order to target VCS repos (they can be of any type), the full URL to their repo is required – that’s why we’re using Github URLs here, and not the package names like we would in a typical require.

The require-* values mean all versions and all their dependencies are to be installed. The archive section makes sure the distributions of the packages are downloaded into dist for full offline access.

Note that I’ve used an actual host name for the URL, not the IP of my machine. I could have used an IP and it would have worked, but only at home – at the conference, the IP of my machine would change, and things would break. You should always define the URL with a host name, rather than an IP.

Once we’ve listed everything we need, we build the local repo with:

php bin/satis build satis.json web/

This will read the satis.json file and save all the packages at all their required versions into web/ (depending on the number of packages and the version required, this can take a while). You’ll likely be asked for a Github token to get past the download limit. If so, just follow the on screen instructions.

Note that the above setup is absolutely brutal in terms of installation times because Satis will download and install all version of all packages, and all their binary distributions. This is handy when altering/developing these packages, but not in everyday use. I recommend you define the exact versions of packages you need, rather than requiring “all”.


Now that the packages have been downloaded, we need to point a server at the web folder, so that it’s accessible via the web. Composer will download packages from it via HTTP, so some basic web hosting needs to be put in place. This doesn’t need to be robust, so a simple PHP built-in webserver instance will do just fine:

cd web
php -S

The server is now live, and the index page should be accessible from the host machine. For example, if you added an etc/hosts entry like nofw.websc (this was my host entry for the conference), you should be able to open it as such:

nofw.websc satis opens

This screen lists all installed packages at their installed versions, and lets you search them.

If you have a phone connected to your wifi, you should be able to access the same screen by using your host machine’s IP address. At the time of writing, my Macbook’s IP address was, so I could access it via

opening the satis webhost on a mobile device

That’s not very useful, though, so let’s try and access it from another machine to make sure it works. I’ll try my Windows 10 laptop:

opened the satis instance in the Edge browser on Windows 10

Sure enough, it works.


Finally, let’s try and pull some of those packages in on the Windows machine. Naturally, I use Vagrant there as well. I’ll assume you’ve also set up a new Homestead Improved instance for trying this out.

Once it’s up and running, we need to modify the etc/hosts file of the VM to include the “address” of our repo – corresponding to the one in satis.json. In my case, that’s: nofw.websc

Then, as per instructions on the home page of our Satis repo, we add the repositories key into the composer.json file of the projects we want to pull from our Satis server:

    "repositories": [
            "type": "composer",
            "url": "http://nofw.websc:6789"
    "config": {
        "secure-http": false

We have to use secure-http: false because we’re serving from a local server, one without an SSL certificate. By default, Composer won’t let us install anything over HTTP.

Now, we can require packages in that project as usual:

composer require twig/twig beelab/bowerphp

Composer should now take into account our new repo address, and pull from there:

Composer pulling from the custom address


This section will list some common problems and their solutions.

Windows won’t open “intranet” (192.168.x.x) sites

The issue can be a WiFi extender which mimics the main network – it replicates the SSID and password to allow for seamless connection throughout the house. The problem is that if the devices aren’t connected to the same device (all on router, or all on extender) this intranet communication won’t work.

To solve the problem, make sure all devices are connected to the same router / extender by, for example, powering off the extender.

Connection refused

Make sure you opened the ports in Homestead.yaml, like so:

     - send: 6789
       to: 6789

If you’re using another Vagrant box which doesn’t have this simple setup procedure, go raw and modify the ports in the Vagrantfile.

Why not use Ngrok or Localtunnel?

Because Ngrok and Localtunnel require internet access, and need a stable connection. They’re just for sharing a local server with the public, not for sharing stuff via WiFi.


In this tutorial, we saw how easy it is to host your own required Composer packages locally, so that everyone in an offline environment, or an environment with an unstable internet connection, can still connect and download all packages. This is useful not only for conferences, but also as a “packagist backup” for companies – no more downtime when Github is down!

Another idea is putting together a small Raspberry Pi box with this exact same setup, and carry it with you. That way, there’s no need to host a heavy Vagrant image, and you still have all your needed packages with you – ready to be shared with anyone connecting to your Wifi. Developing on a train or plane and want to share your work with another tethered colleague? No problem! Just boot up the RasPi hosting your Satis and it’s ready to roll!

Frequently Asked Questions (FAQs) about Local Composer and Satis Setup

What is the main difference between Satis and Packagist?

Satis and Packagist are both package repositories for Composer. However, the main difference lies in their functionality and usage. Satis is a static Composer repository generator. It allows you to host your own Composer packages privately, which is particularly useful when you want to distribute private packages within your organization. On the other hand, Packagist is the main Composer repository. It is a public platform where you can publish your open-source PHP packages for everyone to use.

How can I set up Satis on my local machine?

Setting up Satis on your local machine involves a few steps. First, you need to install Composer. Once Composer is installed, you can install Satis using the command composer global require composer/satis. After Satis is installed, you can create a satis.json configuration file where you specify the repositories you want to include in your Satis repository. Finally, you can build your Satis repository using the command php bin/satis build satis.json public.

Can I use Satis to host private packages?

Yes, Satis is an excellent tool for hosting private packages. It allows you to create a private repository of Composer packages that can be used within your organization. This is particularly useful when you have proprietary code that you don’t want to publish on public repositories like Packagist.

How can I update my Satis repository?

Updating your Satis repository is as simple as running the build command again. The command php bin/satis build satis.json public will regenerate your Satis repository, including any changes you’ve made to the satis.json configuration file. This means that any new packages or versions you’ve added to your repositories will be included in the updated Satis repository.

How can I use Satis with Composer?

Once you’ve set up your Satis repository, you can use it with Composer by adding it to your composer.json file. In the repositories section of your composer.json file, you can add your Satis repository as a new repository. Then, you can require packages from your Satis repository just like you would from Packagist.

Can I use Satis to host packages from multiple repositories?

Yes, Satis can host packages from multiple repositories. In your satis.json configuration file, you can specify multiple repositories that you want to include in your Satis repository. When you build your Satis repository, packages from all the specified repositories will be included.

How can I secure my Satis repository?

There are several ways to secure your Satis repository. One way is to host your Satis repository behind a secure server that requires authentication. Another way is to use SSH keys for authentication when accessing your Satis repository. You can also use HTTPS to encrypt the communication between your Satis repository and the clients accessing it.

Can I use Satis to host non-PHP packages?

Satis is primarily designed to host PHP packages for Composer. However, it can also host other types of files as long as they are included in a Composer package. This means that you can use Satis to host JavaScript, CSS, or other types of files as long as they are part of a Composer package.

How can I automate the updating of my Satis repository?

You can automate the updating of your Satis repository by setting up a cron job or a similar task scheduler. The task should run the Satis build command at regular intervals to ensure that your Satis repository is always up-to-date.

Can I use Satis to host packages from private repositories?

Yes, Satis can host packages from private repositories. In your satis.json configuration file, you can specify private repositories that you want to include in your Satis repository. You will need to provide the necessary authentication credentials for Satis to access the private repositories.

Bruno SkvorcBruno Skvorc
View Author

Bruno is a blockchain developer and technical educator at the Web3 Foundation, the foundation that's building the next generation of the free people's internet. He runs two newsletters you should subscribe to if you're interested in Web3.0: Dot Leap covers ecosystem and tech development of Web3, and NFT Review covers the evolution of the non-fungible token (digital collectibles) ecosystem inside this emerging new web. His current passion project is RMRK.app, the most advanced NFT system in the world, which allows NFTs to own other NFTs, NFTs to react to emotion, NFTs to be governed democratically, and NFTs to be multiple things at once.

BrunoScomposerhomesteadhomestead improvedOOPHPpackagistPHPsatisvagrant
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form