snxraven 611fb8936d
CI / php (push) Has been cancelled
update
2026-03-21 03:13:02 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:13:02 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:01:08 -05:00
2026-03-21 03:13:02 -05:00
2026-03-12 17:05:22 -05:00

MageSail - Holesail Tunnel Integration for Magento 2

Magento 2 Compatible PHP Version License

Full documentation: docs/README.md (installation, configuration, NGINX, routing plugins, troubleshooting).

Overview

MageSail is a Magento 2 extension that integrates Holesail (P2P tunneling with HyperDHT / Hyperswarm) so you can expose a local Magento dev site without traditional port forwarding or a central SaaS relay. A shareable key (e.g. hs://…) allows remote clients to reach your local HTTP/HTTPS port.

Version: package 1.0.4 — see Magesail/composer.json and Magesail/etc/module.xml (setup_version).

Key features

  • Secure tunneling — Private (authenticated) vs public Holesail modes, mapped to Secure Tunnel Yes/No in Admin.
  • Admin lifecycle — Create, start, stop, and remove tunnels under MageSail → Holesail Tunnel → Manage Tunnel; status polling and per-tunnel log tail via AJAX.
  • Tunnel store views — Each tunnel gets a generated store code (e.g. mgtun_…) on the website / store group you choose, with base URLs you supply. Remove tears down the store and NGINX map line; Stop only stops the Node process (with safety rules if that store is the website default on delete).
  • NGINX global map — Optional append/remove of map $http_host $MAGE_RUN_CODE / $MAGE_RUN_TYPE lines plus nginx -t and reload (or wrapper script). Admin screen: MageSail → Holesail Tunnel → NGINX Global Map.
  • Storefront / admin routing — Plugins detect tunnel traffic via header X-MageSail-Store-Code, query magesail_store, ___store, or hostname vs persisted tunnel URLs; adjust MAGE_RUN_*, backend front name resolution, generated base URLs, and skip redirect-to-base where appropriate.
  • PID and logs — Per tunnel: var/magesail_tunnels/{id}.pid, {id}.key, var/log/magesail_tunnel_{id}.log; optional DB rows in magesail_logs.
  • Cron — Daily job checks each tunnels PID file. If the process is dead and Auto-restart is No, it removes that tunnel (store, NGINX map line, registry row, PID/key) — same end state as Remove for a crashed tunnel. If Auto-restart is Yes, it clears stale PID/key and starts Node again (saved port and secure mode).

Good for client demos, remote QA, and team access without deploying to staging.

Private vs public keys (Holesail)

Holesail supports private (default, authenticated) and public (open) modes. In Admin, Secure Tunnel = Yes means private mode, No means public.

Private mode

  • A seed derives a keypair; the server keeps authentication material; peers need the shared secret to connect.
  • Treat shared seeds like SSH private keys: only share with trusted parties.

Public mode

  • A discoverable public address; anyone with the key can reach the tunnel endpoint.
  • Protect sensitive data with Magentos own auth (customer login, admin ACL, etc.).

Private mode is recommended for most dev sharing.

Requirements

  • Magento 2: 2.4.x (see Composer constraints in Magesail/composer.json).
  • PHP: 8.1, 8.2, or 8.3.
  • Node.js: 18+ for start-server.js.
  • npm: Install dependencies under Magesail/scripts/.
  • OS: Linux/macOS typical; Windows untested (WSL may work). Shell tools: ps, kill, nohup.
  • Composer: For packaged installs.

Holesail and npm dependencies are pulled when you run npm install in the scripts directory (see docs/scripts.md).

Installation

1. Install the package

Composer — package name magesail/magesail:

composer require magesail/magesail:^1.0

If the package is not on Packagist, add a path or VCS repository in the project composer.json, then composer require magesail/magesail:@dev.

Set MageSail → Holesail Tunnel → Configuration → Scripts directory to the absolute path of the folder that contains start-server.js, e.g. <magento-root>/vendor/magesail/magesail/scripts.

Git clone under app/code:

cd <magento-root>/app/code/
git clone <repository-url> MageSail

Module root: app/code/MageSail/Magesail/.

2. Enable the module

php bin/magento module:enable MageSail_Magesail
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:flush

3. Verify

  • php bin/magento module:status MageSail_Magesail → enabled.
  • Admin: MageSail → Holesail Tunnel (Manage Tunnel, NGINX Global Map, Configuration).
  • Database: table magesail_logs.

4. Node dependencies (one-time)

cd <magento-root>/app/code/MageSail/Magesail/scripts
# or: cd <magento-root>/vendor/magesail/magesail/scripts
npm install

Configuration

All settings: MageSail → Holesail Tunnel → Configuration (standard Magento config UI; not listed under Stores → Configuration).

Tunnel settings

Field Default Description
Secure Tunnel Yes Private vs public Holesail mode.
Scripts directory (empty) Absolute path to start-server.js folder. Empty = default under app/code/MageSail/Magesail/scripts from Magento root.
Node.js binary (empty) Empty = node on PHPs PATH. Set a full path if Node is not on PATH (nvm, fnm, etc.).
Auto-restart on crash No If Yes, the monitor cron restarts each tunnel whose process died (saved port and secure mode). If No, the monitor tears down tunnels with a stale PID (store + map + registry), not only the PID files.
Monitor cron schedule 0 0 * * * Magento cron expression for the tunnel health job (default: daily at midnight). Edit in Configuration → Settings.

Scoped globally / per website / per store view. After changes: php bin/magento cache:flush config.

NGINX configuration

Used when you manage MAGE_RUN_CODE / MAGE_RUN_TYPE via a shared global map file (e.g. Ansible). Fields include Global map file path, nginx binary path, Temporary PID file (for isolated nginx -t), Reload wrapper script (when PHP cannot nginx -s reload), map variable names, MAGE_RUN_TYPE value, and Disable base URL redirect for tunnel. See docs/configuration.md and docs/nginx-global-map.md.

Advanced (app/etc/config.php): you can set magesail/settings/* and magesail/nginx/* keys to match system.xml paths.

Usage

Admin menu

  • MageSail → Holesail Tunnel → Manage Tunnel — start/stop, base URLs, key display, log snippet.
  • MageSail → Holesail Tunnel → NGINX Global Map — edit/validate/reload the configured map file (requires config ACL).
  • MageSail → Holesail Tunnel → Configuration — tunnel defaults, scripts path, Node binary, monitor cron schedule, auto-restart, NGINX paths (requires config ACL; opens standard system config for section magesail).

Starting a tunnel

  1. Open Manage Tunnel.
  2. Under Add tunnel, choose Website and Store group, Local port (preset 443, 80, 8080, or Custom), and Tunnel hostname (unsecure) (required), e.g. dev.myshop.localno http://; Magento stores http://…/ automatically. It must match the host in the browser / Holesail client vhost.
  3. Optionally set Tunnel hostname (secure), Use secure URLs on storefront and in admin, and Holesail secure tunnel. Full http:// / https:// URLs still work if pasted.
  4. Click Create and start tunnel.

The module creates a new store view with a generated code (e.g. mgtun_…), persists var/magesail_tunnels.json, may update the NGINX map, then starts Node. PID and key live under var/magesail_tunnels/{id}.pid and .key. The UI polls magesail/tunnel/status (optionally with tunnel_id) until the key appears.

For an existing stopped tunnel, use Start on that row (no re-provision).

If the map was updated but nginx could not reload (common for the PHP user), follow the on-screen hint or docs/nginx-global-map.md.

Proxy / client routing

So Magento resolves the tunnel store, your proxy or browser can use the tunnels store code from Admin (example: mgtun_abc12345):

  • Header: X-MageSail-Store-Code — value = that store code
  • Query: magesail_store= + store code
  • Or native: ___store= + store code

If the request host matches the provisioned tunnel base URL host, detection can work without those hints. Details: docs/request-routing-and-plugins.md.

Sharing access

  • Copy the hs://… (or key string shown) for Holesail clients.
  • Local port override example: holesail hs://… --port 1234 then curl http://127.0.0.1:1234/.
  • You may add the shop hostname to /etc/hosts pointing at 127.0.0.1 when using a local listener.
  • TLS to localhost often uses dev certs; browsers may warn.

Stopping or removing a tunnel

  • Stop — Kills the Node process and removes that tunnels PID/key files. The store, NGINX map line, and registry row stay so you can start again.
  • Remove — Stops the process, removes the NGINX map line, deletes the store view when allowed, and removes the tunnel from the registry.

Manual: kill $(cat var/magesail_tunnels/<id>.pid) and remove stale *.pid / *.key under that directory if needed.

Monitoring

  • UI — running state, PID, key.
  • File logtail -f var/log/magesail_tunnel_<id>.log (per tunnel)
  • Databasemagesail_logs for start/stop/cron messages.

Cron

  • Schedule: configurable under Configuration → Settings → Monitor cron schedule (stored as crontab/default/jobs/magesail_monitor/schedule/cron_expr; default 0 0 * * *). Magesail/etc/crontab.xml points at that path; default is also in Magesail/etc/config.xml.
  • Behavior: For each tunnel, if its PID file exists but the process is dead: with Auto-restart on crash = No, the job runs full teardown for that tunnel (as after Remove, subject to the same website-default rules). With Auto-restart = Yes, it removes stale PID/key, then starts Node using that tunnels saved local port and Holesail secure flag. A warning is logged either way.

Troubleshooting

Short table — expanded in docs/troubleshooting.md.

Issue Suggestion
Start fails / “Command failed” Node.js binary in Configuration if node is not on PHPs PATH; run npm install in Scripts directory.
“Tunnel hostname is required” Fill unsecure hostname before start.
Invalid port Use a local port between 1 and 65535 (presets or custom). If two tunnels share a port, the second Start may fail unless your OS/stack allows multiple binds.
Stale PID Delete var/magesail_tunnels/<id>.pid manually or use Start after a clean stop. If you wait for daily cron with Auto-restart = No, the module may remove the whole tunnel (not only the PID file). Check for zombie start-server.js.
301 to production URL Tunnel plugins + NGINX map + reload; see docs/tunnel-store-and-multistore.md.
Reload / map permission errors Map file writable by PHP user; wrapper + sudoers — Magesail/scripts/README-NGINX-RELOAD.md.
start-server.js / node_modules errors on start Scripts directory must contain start-server.js and a node_modules folder after npm install.

Development / CI

From the repository root (not only inside Magesail/):

composer install
./vendor/bin/phpunit -c phpunit.xml.dist
./vendor/bin/phpstan analyse --memory-limit=512M
./vendor/bin/phpcs --standard=phpcs.xml

CI (Gitea Actions): primary workflow .gitea/workflows/ci.yml. Gitea checks .gitea/workflows before .github/workflows, so that file is what runs on Gitea. On Gitea 1.19+, enable Actions if needed ([actions] ENABLED=true before 1.21), register an act runner, and ensure a runner accepts runs-on: ubuntu-latest (or change the workflow to match your runner labels). .github/workflows/ci.yml duplicates the same steps for GitHub Actions (short uses: names); edit both when you change CI (the Gitea file uses explicit https://github.com/... action URLs, which Gitea documents for predictable resolution). The modules Magesail/composer.json targets Magento 2.4.x (magento/framework >=103.0 <106, etc.); install that package inside a Magento project with Composer + repo.magento.com credentials.

License

This project is licensed under the GNU General Public License v3.0 or later — see LICENSE and Magesail/composer.json.

S
Description
No description provided
Readme
1.1 MiB
Languages
PHP 69.3%
HTML 14.7%
JavaScript 13.7%
CSS 2.1%
Shell 0.2%