Skip to main content

Launch, supervise, and reconnect to long-running HTTP services locally or over SSH, with optional tunneling.

Project description

remote-http-launcher

remote-http-launcher is a command-line tool and Python library for launching, supervising, and reconnecting to long-running HTTP services — either locally or on remote hosts via SSH. It is driven by a single YAML configuration file that describes the service to launch, and it manages all process lifecycle state through JSON files on the client and server side.

Although it originated in the Seamless scientific-workflow framework, remote-http-launcher is fully generic: it can launch any HTTP service that follows its status-file protocol.

How it works

Given a YAML config, the launcher follows a deterministic sequence:

  1. Check for an existing local connection file (~/.remote-http-launcher/client/<key>.json). If one exists and the service responds to the configured handshake, the launcher exits immediately — the service is already running.

  2. Check the remote (or local) server directory (~/.remote-http-launcher/server/<key>.json):

    • If the remote JSON shows "status": "running", the launcher verifies the port and handshake, then writes the local connection file.
    • If it shows "status": "starting", the launcher monitors until the service comes up (or times out).
    • If the JSON file is absent or stale, the launcher starts the service.
  3. Launch the service as a daemonic subprocess (locally or over SSH), writing a server-side JSON file with the PID, workdir, and "status": "starting". The path to this JSON file is passed to the service via the {status_file} template variable in the command field.

  4. Optionally create an SSH tunnel forwarding the remote port to a local port, with a background monitor that tears down the tunnel when the remote process exits.

  5. Write the local connection file containing the hostname and port (local or tunneled) for consumption by client code.

Status-file protocol

remote-http-launcher imposes a specific contract on any service it launches. The service must:

  1. Read the JSON status file whose path was passed to it (via the {status_file} template variable in the command).
  2. Acquire a free port and start listening on it.
  3. Update that same JSON file: set "status" to "running" and add a "port" field with the chosen port number.

If the service fails to start, it should set "status" to "failed".

The launcher monitors the status file after starting the process. If the file is not updated within roughly one minute (and the process has exited), the launcher treats the launch as failed.

This is the only requirement remote-http-launcher places on the launched service — beyond this protocol, the service can be anything that speaks HTTP.

Configuration

The YAML configuration file supports the following fields:

Field Required Description
workdir yes Working directory on the (remote) host
key yes Template string evaluated to a filename used for the JSON state files
command yes Template string for the bash command to launch the service
hostname no Target HTTP hostname or IP; omit to run locally
ssh_hostname no SSH host to connect to (defaults to hostname)
network_interface no Interface the service binds to (default: localhost)
tunnel no Create an SSH tunnel for the service port (default: false)
handshake no HTTP path (and optional query parameters) for a health-check GET request
conda no Conda environment to activate before launching the command
file_parameters no Arbitrary parameters written into the server-side JSON file

The key and command fields are Python f-string templates evaluated against the full config namespace.

Example

workdir: /home/user/my-service-data
hostname: my-server.example.com
key: 'myservice-{workdir.strip("/").replace("/", "--")}'
command: >-
  myservice --port-range {port_start} {port_end}
  --status-file {status_file}
  --host {config['network_interface']}
  --timeout {timeout}
  {workdir}
network_interface: "0.0.0.0"
handshake: healthcheck
conda: myservice-env
timeout: 600
port_start: 10000
port_end: 19999

A JSON schema is included at config.schema.yaml for validation and editor support.

Installation

pip install remote-http-launcher

The only runtime dependency is PyYAML.

Usage

# Launch (or reconnect to) the service described in config.yaml
remote-http-launcher config.yaml

# Override the client connection directory
remote-http-launcher config.yaml --connection-dir /tmp/my-connections

# Print the evaluated command without launching
remote-http-launcher config.yaml --dry-run

Python API

from remote_http_launcher import run

result = run({
    "workdir": "/home/user/data",
    "key": "my-service",
    "command": "myservice --port-range 10000 19999 --status-file {status_file} {workdir}",
    "handshake": "healthcheck",
})
print(result["hostname"], result["port"])

SSH Guard

remote-http-launcher ships an SSH guard (rhl-guard) that restricts what commands can be run on the remote server under the service user account. When installed, only the specific command patterns sent by the launcher itself and a set of named helper programs are permitted — naked shell commands such as pkill, rm -rf, or arbitrary python3 -c are rejected.

How it works

The SSH command= option in authorized_keys forces every incoming SSH session through rhl-guard. The guard reads SSH_ORIGINAL_COMMAND, validates it against a whitelist, and either execs the command or exits with an error. Interactive sessions (no SSH_ORIGINAL_COMMAND) are always rejected.

The whitelist covers:

  • bash -lc commands matching the exact patterns that remote-http-launcher generates: ps -p <int> -o pid= and Python heredoc scripts bearing the launcher's __RHL_REMOTE_SCRIPT__ sentinel.
  • Inside Python heredoc launch scripts, the guard verifies that the service binary is one of the tools listed in ssh_guard/tools.yaml (a vendored copy of the Seamless tools.yaml).
  • Any rhl-* helper command installed by this package (see below).
  • Conda probe fallbacks (command -v conda, cat ~/.bashrc, etc.) — only reached on servers where the conda cache has not been primed.

Direct process-management commands such as kill -1 <pid> are rejected by the guard. Use helpers such as rhl-kill-service <key> instead.

Installation

On the remote server, add to ~/.ssh/authorized_keys:

command="rhl-guard" ssh-rsa AAAA... your-key-comment

If you use a non-standard tools.yaml, set RHL_TOOLS_YAML=/path/to/tools.yaml in the server environment.

Conda cache (guarded servers)

When the guard is active, the launcher replaces the individual conda probe SSH commands with a single cached read. Prime the cache once after installing the guard:

ssh <remote_host> rhl-cache-conda

Re-run this if the conda environment changes. On unguarded servers the launcher falls back to its original probe behavior automatically — rhl-cache-conda is a no-op there too.

Helper commands (rhl-*)

Installing remote-http-launcher adds a set of server-side helper programs that perform specific, safe operations on launcher state. These are the commands agents and operators should use instead of raw kill, rm, or shell loops.

Command Description
rhl-guard SSH guard entry point — validates SSH_ORIGINAL_COMMAND before exec
rhl-cache-conda Discover conda setup and write ~/.remote-http-launcher/conda-setup.json
rhl-cat-log <key> Print the stdout/stderr log for a service
rhl-cat-json <key> Pretty-print the server state JSON (PID, port, status, workdir)
rhl-ls-services [--client] List service keys (server-side by default, --client for local)
rhl-kill-service <key> Send SIGHUP to the service PID and remove its server state JSON
rhl-rm-state <key> [--client] [--server] Remove state JSON files (default: both)
rhl-restart-cluster <cluster> SIGHUP all services for a cluster and clean up their state files
rhl-clear-buffer <path> Remove all files directly inside a buffer directory
rhl-clear-db <path> Remove seamless.db from a database directory

rhl-clear-buffer and rhl-clear-db validate that the target path is absolute and not a system directory before touching anything.

All state-file helpers respect the REMOTE_HTTP_LAUNCHER_DIR environment variable (same as the launcher).

CLI scripts

Installing remote-http-launcher also provides:

  • remote-http-launcher — main launcher CLI
  • All rhl-* helpers listed in the table above

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remote_http_launcher-0.3.0.tar.gz (30.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

remote_http_launcher-0.3.0-py3-none-any.whl (31.3 kB view details)

Uploaded Python 3

File details

Details for the file remote_http_launcher-0.3.0.tar.gz.

File metadata

  • Download URL: remote_http_launcher-0.3.0.tar.gz
  • Upload date:
  • Size: 30.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for remote_http_launcher-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f244438525df9430bcb4924ed542cb38a8f34f13ae36af208f7b565b98962214
MD5 fea0a59f0b1e5e22c7430da4fa278b0c
BLAKE2b-256 f8824784424ee852f8856bc5354db7f404d5d5b07f76c4cbcd8eac0ec15e1c02

See more details on using hashes here.

File details

Details for the file remote_http_launcher-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for remote_http_launcher-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 656387d912ad8c7d826ce2a91137fee8d9c8f37726fcbb87ae6d0578b6755914
MD5 a35871cae3744282d5cb350235bcc340
BLAKE2b-256 7d47c09df04e513225a146930b117b2a777551afa7591b0b4bdc4468dcb305de

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page