Port offset

SPLENT automatically adjusts feature port numbers per product so you can run multiple products on the same host without collisions.

Table of contents

Why it exists

Every infrastructure feature declares host ports in its .env.example (e.g. REDIS_HOST_PORT=6380, PMA_HOST_PORT=8081). If two products use the same features, their ports would collide. The port offset solves this by shifting every feature port by a deterministic, product-specific amount.


How it works

When product:env --merge runs, it does the following.

  1. Scans the merged environment for variables that look like port declarations (ending in _HOST_PORT, _PORT_ONE, _PORT_TWO).
  2. Computes a deterministic offset from the product name.

    offset = crc32(product_name.encode("utf-8")) % 1000
    
  3. Adds the offset to each detected port value.
  4. Writes the adjusted values to the product’s merged .env.

The offset is stable. The same product name always produces the same offset, so ports don’t change between runs.


Example

For a product named my_first_app (offset 591), the adjustments look like this.

Feature Variable Base port Adjusted port
Redis REDIS_HOST_PORT 6380 6971
phpMyAdmin PMA_HOST_PORT 8081 8672
Mailhog SMTP MAILHOG_SMTP_HOST_PORT 1025 1616
Mailhog UI MAILHOG_UI_HOST_PORT 8025 8616

The merge output confirms adjustments.

  ports    adjusted 4 feature port(s) (+591)
  merged   4 feature .env file(s) into product .env

What is and isn’t adjusted

Only feature port variables are adjusted. Product-level ports (like the web server port in docker-compose.dev.yml) are never touched.

Three rules apply.

  • Variables ending in _HOST_PORT, _PORT_ONE, or _PORT_TWO are adjusted.
  • Feature ports that already exist in the product’s .env are left unchanged (product values take precedence).
  • The offset only applies during product:env --merge. Base values in each feature’s .env.example are never modified.

Implications for feature authors

When creating a new infrastructure feature with Docker services, follow these steps.

  1. Use an _HOST_PORT suffix for your port variable (e.g. NGINX_HTTP_HOST_PORT=80).
  2. Pick a sensible base value that doesn’t overlap with common system ports.
  3. Reference the variable in your docker-compose.yml.

    ports:
      - "${NGINX_HTTP_HOST_PORT}:80"
    
  4. The offset mechanism handles the rest, with no extra code needed.

The offset only means anything because each product runs its own instance of the feature’s stack: a port of one’s own presupposes a container of one’s own to publish it. That is the other half of the same rule, and it comes with three more conditions on the compose file.



Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es