Sometimes you need to trigger a command on a server over HTTP: from an automation system, from a script on another machine, from a pipeline. Spinning up a Python service with a framework for that is overkill. That’s how http2shell came about — an HTTP API server written entirely in Bash.

Why

I was automating bug bounty workflows in n8n and hit a limitation: n8n doesn’t keep shell command output larger than 1 MB. For recon tools that produce megabytes of subdomains and URLs, that’s a dealbreaker. The fix was to move command execution into a separate HTTP service and fetch the result with a regular HTTP request.

The idea was inspired by an article on Habr about an HTTP server in Bash; I grew it into a tool with authentication, custom endpoints and timeouts.

Features

  • pure Bash, no frameworks;
  • HTTP Basic Authentication;
  • built-in system information endpoints;
  • arbitrary command execution (can be disabled);
  • custom endpoints: URI → command;
  • the system shell by default or any shell you choose;
  • timeouts for command execution and for reading the request body;
  • colored logs (can be turned off).

Dependencies are minimal: bash, socat, jq, timeout, dd, sha256sum and standard utilities.

Installation and launch

apt install socat jq          # Debian/Ubuntu
git clone https://github.com/solo10010/http2shell.git
cd http2shell
chmod +x http2shell.sh
./http2shell.sh

By default the server listens on 127.0.0.1:8007 with Basic Auth rest:api (change it!) and the /exec endpoint enabled.

Options

-ip, --ip <ip>                  address (default 127.0.0.1)
-port, --port <port>            port (default 8007)
-u, --user / -p, --pass         Basic Auth login and password
-s, --shell <path>              shell used to run commands
--no-exec                       disable /exec and /execf
-e, --endpoint <uri> <command>  add a custom POST endpoint
--cmd-timeout <sec>             execution timeout (default 20)
--body-timeout <sec>            request body read timeout (default 10)
--no-color                      no colored logs

Examples

System information:

curl -u user:pass http://127.0.0.1:8007/api/uptime
curl -u user:pass http://127.0.0.1:8007/api/disk

Running a command:

curl -u user:pass -X POST http://127.0.0.1:8007/exec -d "id"

A custom endpoint instead of arbitrary execution — the preferred option:

./http2shell.sh --no-exec --endpoint /api/procs "ps aux"
curl -u user:pass -X POST http://127.0.0.1:8007/api/procs

Using it from n8n

In n8n it’s a regular HTTP Request node:

  • method POST;
  • URL — the http2shell address and endpoint (/exec or a custom one);
  • authentication — Basic Auth;
  • body — the command as text.

The response comes back as a normal HTTP response, without the 1 MB limit, and is processed further in the workflow.

Security comes first

A service that runs commands over HTTP is remote code execution by definition. So:

  • never expose http2shell to the internet. Only 127.0.0.1 or an internal network / VPN;
  • change the default login and password;
  • disable /exec (--no-exec) and use only predefined endpoints with fixed commands;
  • run it as an unprivileged user, not root;
  • Basic Auth sends the password in clear text — if traffic leaves localhost, put a reverse proxy with TLS in front of the service;
  • restrict access with a firewall.

The tool was built for internal automation, DevOps tasks, training labs and CTFs — those are the scenarios where it belongs.

Takeaways

http2shell shows that simple tasks don’t require pulling in a framework: Bash and socat give you a working HTTP API in a few hundred lines. And the main lesson: any “convenient way to run a command remotely” must be designed with access restrictions from the start, or it becomes someone else’s backdoor.