PHPackages                             bedezign/dchelper - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [CLI &amp; Console](/categories/cli)
4. /
5. bedezign/dchelper

ActiveLibrary[CLI &amp; Console](/categories/cli)

bedezign/dchelper
=================

Augment docker-compose with extra developer-friendly functionality

0.0.5(8y ago)113MITPHPPHP ^7.0

Since Jan 28Pushed 8y ago1 watchersCompare

[ Source](https://github.com/bedezign/dchelper)[ Packagist](https://packagist.org/packages/bedezign/dchelper)[ Docs](http://github.com/bedezign/dchelper)[ RSS](/packages/bedezign-dchelper/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (5)Dependencies (5)Versions (6)Used By (0)

Docker Compose Helper
=====================

[](#docker-compose-helper)

**(STILL IN DEVELOPMENT, use at your own risk)**

> Please note that the network related functionality in this helper (alias/proxy) **only works on macOS**. I'm really sorry about that. I would love to help Windows people as well, but fact is that it simply does not support most of the required functionality.

If you use docker compose and you want to be able to develop using a decent url for your project like ** instead of ** with nearly no extra setup, then read on!

This tool wraps around docker-compose and will be ran instead of it so it can add some exiting new functionality to your development environment.

Please note that this script **will need sudo** rights for some of the commands.

Installing
----------

[](#installing)

You can simply add it via packagist/composer:

```
composer global require bedezign/dchelper

```

After that you might want to setup an alias in your `.bashrc` file:

```
alias docker-compose="php ~/.composer/bin/dchelper"

```

It's as easy as that!

Notes
-----

[](#notes)

- Currently `dchelper` assumes that there will be "one of each service". It is mainly for development purposes and until someone requests support for multiple containers per service I'm not going to think about the added complexity.
- Mapping IP &amp; Hostname is currently for the first found IP only (with a preference for aliased instead of proxied).

What does it do?
----------------

[](#what-does-it-do)

In short:

- Provides you with a "dedicated IP" for your project (instead of `127.0.0.1`)
- Get rid of having to specify ports
- Automatically create/maintain a hostname for your project. Use [myproject.test](myproject.test) in your browser instead of an IP!
- Easily "shell" into a container (`docker-compose shell` and you have a login-shell into the default container).
- Built-in helpers for docker-compose v3.4 (or higher) configurations (there's "envsubst" and "scriptrunner" at this moment, suggestions welcome)
- All of this via environment variables (`.env`) or docker-compose.yml settings.

### Ports, ports, ports!

[](#ports-ports-ports)

When publishing a port from a container, by default the docker VM maps this onto your `localhost` (`127.0.0.1`).

If you don't specify a remote port, you won't get port collisions but you'll end up with some obscure port like `32122`. I don't know about you, but hosting my development site at `http(s)://127.0.0.1:32122` just doesn't seem right. Even assigning a host to it doesn't make it any prettier when you always have to specify a port.

The alternative would be to map it to the default remote port, but then you'll probably end up with "port in use" etc.

Docker actually has its own solution for this and DCHelper adds a second one.

The premise is that we can add an extra virtual IP per docker-compose-project. That would mean that heavily used ports like 80 and 443 are always available on "your" IP.

There is already a solution built-in in your OS: Linux (and by extension macOS) allow you to add "virtual" IPs to your loopback network interface (aka IP alias). Both docker and `dchelper` can use this functionality to simplify your life a bit.

### Remote IPs (docker)

[](#remote-ips-docker)

Docker (and Docker Compose) define a port specification as follows: `[[remote_ip:]remote_port[-remote_port]:]port[/protocol]`

This means that, when you are adding a published port, you can also specify the IP on which you want the port to be added:

```
container:
  ports:
    - 172.99.0.6:80:80

```

So the above tells docker to link service port `80` to port `80` on IP `172.99.0.6` (instead of `127.0.0.1`). Pretty awesome no? There is a small gotcha however: `docker-compose` will not add the aliased IP to your network interface.

DCHelper will.

It interprets the docker-compose config in advance (as well as your `.env` if one was found) and determines what IPs need to be aliased for your configuration to work.

If it finds any that don't exist yet, it will register them for you before passing control to docker-compose.

Using this functionality is easy: The only modification needed to your configuration is what was shown in the example above.

More extensive example:

`.env`:

```
COMPOSE_ALIAS_IP=172.99.0.1

```

`docker-compose.yml`:

```
services:
  db:
   ports:
      - ${COMPOSE_ALIAS_IP}:3306:3306

  nginx:
    ports:
      - ${COMPOSE_ALIAS_IP}:80:80

```

By using a configured value you don't have much work to update the IP later on. Since the variable will be replaced by docker-compose, DCHelper will still pick up the actual IPs.

`COMPOSE_ALIAS_IP` has a special meaning: DCHelper will always alias this IP, even if it wasn't used further in your configuration. The variable is also used by the **hosts** functionality.

This means slightly more in your configuration file, but docker takes care of the rest, no external utilities needed.

### TCP Proxying/Tunneling (via socat)

[](#tcp-proxyingtunneling-via-socat)

This functionality uses [`socat` (SOcket CAT)](http://www.dest-unreach.org/socat/doc/socat.html), which is a pretty awesome tool that describes itself as a "Multipurpose relay". (It can be easily installed on a mac via HomeBrew)

For this variant your ports-configuration remains as is:

```
container:
  ports:
    - 80

```

The trick here is that you either add a global `COMPOSE_PROXY_IP` environment variable, or specify a `PROXY_IP` in the containers' environment:

```
container:
  ports:
    - 80
  environment:
    PROXY_IP: 172.99.0.1

```

(Specifying `PROXY_IP` allows you to use different IPs in your setup. Use the `COMPOSE_PROXY_IP` globally if you only need the one IP.)

When parsing the configuration, DCHelper will detect all published ports and where they are linked to. It will then launch a bunch of `socat` instances to establish a tunnel between the proxy IP and the randomly assigned docker port on `127.0.0.1`.

The net effect will be the same as the "Remote IP"-method, so it depends on what you prefer. The disadvantage here is that this only works if you detach from the containers when running the `up` command. The tunneling can only be done after your "up" command finalises (containers need to be running to detect the configuration), which doesn't happen without `-d`

This example yields an identical result:

`.env`:

```
COMPOSE_PROXY_IP=172.99.0.1

```

`docker-compose.yml`:

```
services:
  db:
   ports:
      - 3306

  nginx:
    ports:
      - 80

```

Both port `3306` and `80` will be available via `172.99.0.1`.

As mentioned above: It is possible to use different IPs per service, just use `PROXY_IP` instead.

Hostnames
---------

[](#hostnames)

By adding a `COMPOSE_HOSTNAME` to your environment, you tell DCHelper to check your `/etc/hosts` file and if needed, add a new entry to it. The IP used will be either `COMPOSE_ALIAS_IP` or, if that wasn't set, `COMPOSE_PROXY_IP`.

There is currently no support for a per service/container host, just the global one. (I'll add this if someone requests it, I currently have no need for it)

Shell
-----

[](#shell)

DCHelper adds a `shell`-command. By doing `dchelper shell php` for example, it will trigger a (login) shell for in the related container. This actually runs `docker exec -it  ` in the background, but it will allow you to specify the compose service name instead of having to figure out the docker container name.

Due to [this](https://github.com/moby/moby/issues/33794) and [this](https://github.com/moby/moby/issues/10341) (issues with the pseudo terminal size not being set correctly) the default command currently executed is actually `'/bin/bash -c "export COLUMNS=`tput cols`; export LINES=`tput lines`; exec bash -l"'`.

By using `COMPOSE_SHELL_DEFAULT=service-name` in your environment you can indicate what service to use if none was specified. This can also be done by adding `SHELL_DEFAULT=1` to one of your service environment definitions.

If you have a terminal application that understands escape sequences (like iTerm2), DCHelper can also change the tab title for you. You can either specify a title per service in the services environment using `SHELL_TITLE` or specify a global format via `COMPOSE_SHELL_TITLE`. In this case `{CONTAINER}` will be replaced by the containers' name.

For example: `COMPOSE_SHELL_TITLE="${COMPOSE_HOSTNAME: {CONTAINER}"`. The hostname replacement will be taken care of by docker compose, the `{CONTAINER}` will be replace by DCHelper.

Helpers
-------

[](#helpers)

This only works if you use compose file format v3.4 or later. This is the first version that allows for (ignored) vendor-specific root entries (`x-...`)

### Using helpers

[](#using-helpers)

#### Single helper

[](#single-helper)

You can specify a single command to run:

```
x-dchelper:
  command:
    configuration...

```

```
x-dchelper:
  command:
    configuration...
  command2:
    configuration...

```

#### Multiple helpers

[](#multiple-helpers)

If you want to run the same helper multiple times, you can add some "junk" to create different keys:

```
x-dchelper:
  command.serviceone:
    configuration...
  command.servicetwo:
    configuration...

```

What is behind the dot is discarded, so use whatever you want.

#### Root

[](#root)

You can specify `root` as the helper name and it will set the 'base path' for every relative **source/origin** directory on the local system:

```
x-dchelper:
  root: /generic/docker/folder/
  envsubst:
    files:
      - nginx.template:./.docker/nginx.conf

```

This will use the template from `/generic/docker/folder/nginx.template` and store it in the `.docker/nginx.conf` relative to where `docker-compose.yml` lives. It will also translate `~`-entries for you, in the source, target and root directives.

If you have a global `root` set and want it back to the project directory for a specific section, just set it to empty in that section:

```
x-dchelper:
  root: /generic/docker/folder/
  scriptrunner:
    root:
    files:
      - ./script.sh

```

`script.sh` will be loaded from working directory rather than the `/generic/docker/folder`

#### Stages

[](#stages)

Currently the helpers can run at 2 stages: `pre.` and `post.`. (as in: before and after the `docker-compose up` command). By specifying `at` in the configuration you can override this behavior. `post.up` can only run after the `up` command completes, so if you do not detach it will only run after you terminate the containers. Other possibilities are for example `pre.shell` etc.

### EnvSubst

[](#envsubst)

If your compose project needs configuration files with values based on your environment, the trick so far was splice in an `envsubst` call somewhere that takes care of this for you. DCHelper supports this natively and in a simple manner.

Important: The helper is written in a way that it will *only* replace whatever variables are known in the environment. This will not touch anything except that. So `proxy_set_header Host $http_host;` will be safe, as long as you don't have a `http_host` defined.

Note that this is internal functionality. You don't need to install the `envsubst` command for this to work.

To generate a configuration file, you just add an entry for `envsubst`:

```
x-dchelper:
  envsubst:
    environment-file:
      - .env
    environment:
      - nginx
    files:
      - /generic/template/folder/nginx/site-fpm.conf:./.docker/site.conf

```

This runs @ `pre.up` by default.

#### environment-file

[](#environment-file)

Which files to load as environment files. The default (if not specified) `.env` in the working directory.

#### environment

[](#environment)

The docker-container environments to load.

In the example it will use the `.env` file with the environment from the *nginx* service added on top.

#### files

[](#files)

List of files to do the replacement on. The source (or even target) files do not need to be in the project directory.

This allows you to create a number of templates and then generate a per-project config whenever you run `docker-compose up`.

By using the multiple commands syntax you can run `envsubst` multiple times if you want different environments.

By prepending the name of the output file with a service name the configuration will be created in the relevant container. This path **has to be absolute**. [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp/) is used for this functionality.

Example for the above:

```
 x-dchelper:
   envsubst:
     files:
       - /generic/template/folder/aws/credentials.conf:aws-cli:/home/root/.aws/site.conf

```

`dchelper` will make sure the target folder gets created for you if needed and then copies the file into it.

#### Result

[](#result)

The `envsubst` helper runs before anything else, so the generated files are available in all your services:

```
  nginx:
    image: nginx:latest
    volumes:
      - ./.docker/site.conf:/etc/nginx/conf.d/site.conf

```

### ScriptRunner

[](#scriptrunner)

`scriptrunner` allows you to run shell scripts within the container. It doesn't matter if the script is mapped into the container or not, it executes it as a set of bash commands.

This runs @ `post.up` by default if nothing was specified.

An example:

```
x-dchelper:
  scriptrunner:
    service: php
    once:
      - /my/script/dir/php/install_pdo.sh
      - /my/script/dir/php/install_xdebug.sh

```

Note that `scriptrunner` supports `EnvSubst`.

The functionality works both for the command lines (always enabled), so `${SCRIPT_FOLDER}/script.sh` will work). Substituting in the scripts' content also enabled by default, but can be turned of by specifying `envsubst: false`. As with `EnvSubst` you can specify the `environment-file` and `environment`-key as well for more configuration.

#### service

[](#service)

What service/container to run against. If you want to run the script on the host itself, use `localhost`. The `once` behavior is currently not supported for scripts running on `localhost`, only for containers.

#### lock-file

[](#lock-file)

This file is added to the container and used to remember which scripts already ran. Used by the "once" command. If not specified it will default to `/.dchelper.scripts`

#### once vs always

[](#once-vs-always)

You can specify scripts under either `once` or `always`. I think the difference is self-explanatory.

#### direct

[](#direct)

For scripts running on `localhost` (with `always`) you can specify `direct: true`. This forces dchelper to run the shell script as opposed to loading its content and executing that. Please note that envsubst on the file content will not work like this. Since it is running on `localhost` you can always just source the `.env` file on those scripts.

Full example
------------

[](#full-example)

Below is an example of a full `docker-compose.yml`:

```
version: '3.4'

services:
  php:
    image: php:7-fpm
    volumes:
      - .:/project:rw
    environment:
      - XDEBUG_CONFIG=remote_enable=1 remote_mode=req remote_port=9000 remote_host=172.99.0.100 remote_connect_back=0
      - PHP_IDE_CONFIG=serverName=docker-dev

  nginx:
    image: nginx:latest
    volumes:
      - .:/project:rw
      - ./storage/app/docker/site.conf:/etc/nginx/conf.d/site.conf
    ports:
      - ${COMPOSE_ALIAS_IP}:80:80

  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - ~/tmp/dev-data/myproject.test/mysql:/var/lib/mysql:rw
    ports:
      - ${COMPOSE_ALIAS_IP}:3306:3306

x-dchelper:
  root: ~/Steve/Development/Docker
  envsubst:
    environment:
      - nginx
    files:
      - nginx/conf/site_php-fpm_php-9000.template:./storage/app/docker/site.conf
  envsubst.aws:
    at: post.up
    files:
      - aws/conf/credentials.template:php:/root/.aws/credentials
  scriptrunner:
    service: php
    once:
      - debian/scripts/install_aws-cli.sh
      - debian/scripts/install_top.sh
      - debian/scripts/install_ping.sh
      - php/scripts/install_pdo_mysql.sh
      - php/scripts/install_xdebug.sh
      - php/scripts/laravel_artisan_xdebug.sh
      - php/scripts/fpm_reload.sh

```

Part of `.env`:

```
COMPOSE_ALIAS_IP=172.99.0.1
COMPOSE_HOSTNAME=myproject.test
COMPOSE_SHELL_TITLE="${COMPOSE_HOSTNAME}: {CONTAINER}"

APP_URL=https://${COMPOSE_HOSTNAME}

```

What this does: This config will give you a working  that has a port `80` and `3306`. It runs on a 3 container structure, all using unmodified images from the docker hub.

The `root` entry signifies that all relative **source** locations will be mapped in there, the target locations do not use this.
`~` is translated for both target and source.

Note: if the `root` is also relative it will use the current working directory as its base (or home if `~` is used). It can be overwritten locally in a helper configuration.

We use 2 `envsubst` commands here:

- The `nginx`-one creates a locally stored file based on the configuration at the `pre.up` stage. The resulting file is mounted into the `nginx` container so that it can be used when it boots.
- The `aws`-one will create a file directly in the container. Since that functionality only works *after* the container is up, we use `at: post.up` in the configuration.

This also shows that you can use multiple envsubst entries just by appending something random (preferably something that makes sense to you ;) ).

The `scriptrunner` command runs [some of my utility scripts](https://github.com/bedezign/docker-utility-scripts) to install things in the containers and it keeps track of what was installed within that container. `once` indicates that these will only be ran once, if not found in the `lock-file` yet.

Since these will be executed "passthrough", you'll see what is being done in your console without having to look in the container logs to see when things are wrapped up. (which is something that annoyed me personally when using an alternate entry script that installs things).

The `APP_URL` in the example was added to show that you can reuse the variables there as well. The goal here is to have to modify as little as possible to setup a new project.

###  Health Score

24

—

LowBetter than 32% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

5

Last Release

3028d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/78f7fd05d2823bcddf207d7d53ec3a35aefceef528e36c5ebbce774377478c8f?d=identicon)[Blizz](/maintainers/Blizz)

---

Top Contributors

[![Blizzke](https://avatars.githubusercontent.com/u/231572?v=4)](https://github.com/Blizzke "Blizzke (16 commits)")

---

Tags

hostnameshelldockerdocker-composeport-forwardingproxying

### Embed Badge

![Health badge](/badges/bedezign-dchelper/health.svg)

```
[![Health](https://phpackages.com/badges/bedezign-dchelper/health.svg)](https://phpackages.com/packages/bedezign-dchelper)
```

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)[jolicode/castor

A lightweight and modern task runner. Automate everything. In PHP.

53541.0k3](/packages/jolicode-castor)[seregazhuk/php-watcher

Automatically restart PHP application once the source code changes

394137.8k4](/packages/seregazhuk-php-watcher)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
