Compare commits
2
Commits
v1.27.1-6768b0a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5483ff5e1
|
||
|
|
cbb7346fd6
|
@@ -0,0 +1,105 @@
|
||||
# HTTP Toolkit (self-hosted)
|
||||
|
||||
A self-hosted, single-file build of [HTTP Toolkit](https://httptoolkit.com): the
|
||||
server and the web UI compiled into one binary called `httptoolkit`.
|
||||
|
||||
## Install
|
||||
|
||||
Download the latest release into `~/.local/bin`:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/bin
|
||||
wget -O ~/.local/bin/httptoolkit \
|
||||
"https://git.shihaam.dev/shihaam/httptoolkit/releases/download/$(curl -sD - -o /dev/null "https://git.shihaam.dev/shihaam/httptoolkit/releases/latest" | grep -oP '(?<=tag/)[^"\r\n]+')/httptoolkit"
|
||||
chmod +x ~/.local/bin/httptoolkit
|
||||
```
|
||||
|
||||
Make sure `~/.local/bin` is on your `PATH` (most distros do this already):
|
||||
|
||||
```bash
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
```
|
||||
|
||||
## Run as a systemd user service
|
||||
|
||||
Create the unit:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cat > ~/.config/systemd/user/httptoolkit.service <<'EOF'
|
||||
[Unit]
|
||||
Description=HTTP Toolkit (self-hosted)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=%h/.local/bin/httptoolkit --port 8080 --no-open
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
```
|
||||
|
||||
Start it:
|
||||
|
||||
```bash
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user start httptoolkit
|
||||
```
|
||||
|
||||
Then open <http://localhost:8080>.
|
||||
|
||||
### Managing the service
|
||||
|
||||
```bash
|
||||
systemctl --user status httptoolkit # check it's running
|
||||
systemctl --user restart httptoolkit
|
||||
systemctl --user stop httptoolkit
|
||||
journalctl --user -u httptoolkit -f # follow logs
|
||||
```
|
||||
|
||||
Start it automatically at login:
|
||||
|
||||
```bash
|
||||
systemctl --user enable httptoolkit
|
||||
```
|
||||
|
||||
To keep it running when you're not logged in (e.g. on a headless box), enable
|
||||
lingering for your user:
|
||||
|
||||
```bash
|
||||
loginctl enable-linger "$USER"
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
Re-run the download command above, then restart the service:
|
||||
|
||||
```bash
|
||||
systemctl --user restart httptoolkit
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
-p, --port <port> Port to serve the web UI on (default: 8080)
|
||||
--server-port <port> HTK management API port (default: 45457)
|
||||
--mockttp-port <port> Mockttp admin port (default: 45456)
|
||||
--no-open Don't open a browser automatically
|
||||
-h, --help Show this help
|
||||
```
|
||||
|
||||
`--no-open` matters for the service: without it the binary tries to launch a
|
||||
browser on start.
|
||||
|
||||
## Building from source
|
||||
|
||||
Requires Docker. The build runs in a container that clones upstream, applies the
|
||||
patches in `patches/` and the overlay in `overlay/`, then compiles the binary:
|
||||
|
||||
```bash
|
||||
docker compose run --build --rm release-httptoolkit
|
||||
```
|
||||
|
||||
The result lands in `builds/httptoolkit`.
|
||||
@@ -120,4 +120,30 @@ redirect_ws_to_real_package() {
|
||||
echo "==> [node_modules] redirecting ws requires past bun's built-in shim"
|
||||
redirect_ws_to_real_package node_modules/mockttp/dist
|
||||
|
||||
# mockttp decides whether a response is still ongoing or already completed by
|
||||
# sniffing the object's shape:
|
||||
#
|
||||
# // Ongoing response has 'getHeaders' - completed has 'headers'.
|
||||
# if ('headers' in response) return response;
|
||||
#
|
||||
# An ongoing response is a live http.ServerResponse; a completed one is the plain
|
||||
# object built by buildInitiatedResponse(). On node that test works, because
|
||||
# ServerResponse has no `headers` property. Bun's ServerResponse *does* have one
|
||||
# (`'headers' in res` === true, typeof object), so the check is inverted for every
|
||||
# single response: waitForCompletedResponse() bails out immediately and hands back
|
||||
# the live ServerResponse, having neither awaited the body nor attached rawHeaders.
|
||||
#
|
||||
# The admin server then tries to serialise that as a GraphQL Response, whose
|
||||
# schema declares `rawHeaders: Json!`, and the whole responseCompleted event is
|
||||
# dropped with "Cannot return null for non-nullable field Response.rawHeaders."
|
||||
# Traffic still proxies correctly - but the UI only ever receives the *initiated*
|
||||
# response, so exchanges render with status and headers and no body, forever.
|
||||
#
|
||||
# Testing for the ongoing-response method instead is unambiguous under either
|
||||
# runtime: a completed response is a plain object and has no getHeaders.
|
||||
echo "==> [node_modules] fixing mockttp's ongoing-vs-completed response check for bun"
|
||||
replace_literal node_modules/mockttp/dist/util/request-utils.js \
|
||||
"if ('headers' in response)" \
|
||||
"if (typeof response.getHeaders !== 'function')"
|
||||
|
||||
echo "==> patch-node-modules.sh complete."
|
||||
|
||||
Reference in New Issue
Block a user