Install Hunt Web on a Linux Server or VPS
Install Hunt Web on a headless VPS, with private SSH access or an HTTPS domain.
Hunt Web Server brings the CLI, Dashboard, Hermes, scanner tools, and PDF reporting to a VPS without a graphical desktop. It supports Blackbox and Greybox Environment assessments, browser-based progress monitoring, and continuation of an existing Run through Hermes Chat. This guide covers installation, private SSH access or an HTTPS domain, account setup, and a service that stays running after SSH logout.
- 1Prepare the serverUbuntu 24.04 x86_64, a regular sudo user, and at least 30 GiB free.
- 2Choose the access routePrivate SSH or an HTTPS domain. Decide before installing.
- 3InstallRun install.sh in server mode with the chosen origin.
- 4ConnectOpen an SSH tunnel, or publish through Nginx or a Cloudflare Tunnel.
- 5Configure Hermes and the AdminSet the provider, then create the first Admin with the setup code.
- 6Keep it runningInstall the user service and enable lingering.
- 7Check Health and sign inConfirm component status and test a fresh login.
1. Prepare the Server
The supported installer platform is Ubuntu 24.04 x86_64 with Python 3.12. Use a regular account with sudo access, and run installation and configuration as that same account. If the VPS initially provides only root access, create a regular runtime account first.
| Requirement | What to prepare |
|---|---|
| Access | SSH access and a user-owned application directory. |
| Network | Dependency downloads, access to the selected model provider, and outbound connections to assessment targets. |
| Storage | Budget at least 30 GiB free initially, plus room for results, captures, and backups. |
| Ports | Dashboard 3053 and Hermes Gateway 9119 available on the VPS loopback interface. |
| Domain, if used | A domain under the deployment administrator's control and an HTTPS proxy or Tunnel configured separately. |
The installer manages the private Hermes runtime, tools, and Chromium. A separate global Hermes installation is not required beforehand. Server mode does not require a graphical session.
Obtain the release archive and published checksum from the official Hunt Web
release channel, then transfer the archive to the VPS. These examples use
~/hunt-web-2.0.tar.gz:
sha256sum "$HOME/hunt-web-2.0.tar.gz"
Compare the result with the published checksum. Once it matches, extract into a new application directory:
mkdir "$HOME/hunt-web-v2" &&
tar -xzf "$HOME/hunt-web-2.0.tar.gz" --strip-components=1 -C "$HOME/hunt-web-v2" &&
cd "$HOME/hunt-web-v2"
The application lives in ~/hunt-web-v2; private data defaults to
~/.local/share/hunt-web-v2. Keep those directories separate, use paths without
spaces or symlinks, and retain their locations after installation. For an
existing installation, follow the package's upgrade guide instead of
extracting over it.
2. Choose the Access Address Before Installing
Choose one route. During installation, Hunt Web saves its origin: the scheme, hostname, and port used for browser access.
| Route | Saved origin | How users connect |
|---|---|---|
| A. Private SSH | http://127.0.0.1:3053 | An SSH tunnel from their computer to the VPS. |
| B. HTTPS domain | https://dashboard.example.com | A domain served through an HTTPS proxy or Tunnel. |
Choose the access route before installing
Changing DNS later does not change Hunt Web's saved origin. Choose the domain route if the deployment requires domain-based Dashboard access. Moving an existing instance between these routes requires a planned configuration change; do not assume that adding a proxy converts a private installation automatically.
Route A — private SSH:
./install.sh --mode server --time-zone Asia/Jakarta --configure-later
Route B — HTTPS domain: replace the example domain with the deployment's domain, without a trailing slash.
./install.sh --mode server --origin https://dashboard.example.com --time-zone Asia/Jakarta --configure-later
--mode server selects Linux Server / VPS, option 2 in the interactive
installer. Use the required IANA time zone in place of Asia/Jakarta.
--configure-later separates dependency installation from account/model setup.
Wait for installation to complete successfully before continuing. It generates
the instance's dashboard.sh launcher.
The installer does not publish the Dashboard
The installer does not configure DNS, HTTPS, reverse proxies, firewalls, or
Cloudflare. The Dashboard and Gateway remain on loopback; keep ports 3053
and 9119 private.
3. Configure the Access Connection
Follow the subsection matching the selected route, then continue to account setup.
Route A: Open a Private SSH Tunnel
On the client computer, open another terminal and run:
ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:3053:127.0.0.1:3053 operator@vps.example.com
Replace the SSH username and server address. Keep this terminal open. Requests
to http://127.0.0.1:3053 on the client computer will reach the VPS Dashboard
once its launcher starts.
Local port 3053 must be free. If a Desktop instance already uses it, stop
that instance normally when idle, or choose a different port during VPS
installation using --port, then use the matching port in the tunnel and
browser URL. Without the tunnel, the client computer's localhost does not point
to the VPS.
Route B: Publish Through HTTPS
Use an existing HTTPS reverse proxy, the Nginx example below, or the
optional Cloudflare route. Replace dashboard.example.com everywhere with the
exact domain passed to the installer.
Nginx and a Public TLS Certificate
For a new Ubuntu VPS, point the domain's DNS A record to the server. Add an
AAAA record only if the server also serves that domain over IPv6. For this
direct Nginx route, allow inbound HTTP/HTTPS ports 80 and 443 in both the
provider and host firewalls while preserving SSH access. The certificate
method below uses HTTP validation on port 80.
Certbot's Nginx documentation
describes certificate issuance and installation.
Install the proxy and certificate components on the VPS:
sudo apt-get update
sudo apt-get install nginx certbot python3-certbot-nginx
Create /etc/nginx/sites-available/hunt-web.conf, using a new site file rather
than replacing an existing website. Start with this HTTP configuration for
certificate setup:
server {
listen 80;
server_name dashboard.example.com;
location / { return 404; }
}
Enable the site, validate it, then request the certificate:
sudo ln -s /etc/nginx/sites-available/hunt-web.conf /etc/nginx/sites-enabled/hunt-web.conf
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d dashboard.example.com
Complete Certbot's contact and agreement prompts and enable HTTP-to-HTTPS
redirection. Retain the certificate paths and TLS directives it generates.
In the HTTPS server block, replace location / with:
location / {
proxy_pass http://127.0.0.1:3053;
proxy_http_version 1.1;
proxy_set_header Host dashboard.example.com;
proxy_set_header X-Forwarded-Host dashboard.example.com;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $hunt_web_connection;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
client_max_body_size 20m;
}
Add this map at the top of the site file, outside the server blocks. Ubuntu's
standard Nginx configuration includes site files in its http context:
map $http_upgrade $hunt_web_connection {
default upgrade;
'' close;
}
The proxy supplies the public host and scheme, avoids buffering streamed
responses, and forwards connection upgrades. The 20m limit is an example
transport limit; Hunt Web's own upload limits still apply. See the
Nginx proxy directives
and WebSocket proxying guide.
Validate and reload the configuration, then check certificate renewal:
sudo nginx -t && sudo systemctl reload nginx
sudo certbot renew --dry-run
Verify that certificate renewal is scheduled on the VPS. Continue to step 4; the proxy cannot serve Hunt Web until its launcher is running.
Cloudflare Is Optional
Cloudflare Tunnel is an alternative for publishing the same HTTPS origin. Its connector establishes outbound connections from the VPS, so this route can work without opening inbound HTTP/HTTPS ports on the origin server. Follow the official Tunnel setup guide and connection requirements.
Run the connector on the VPS and route the public hostname to
http://127.0.0.1:3053. Ensure the application receives the correct Host,
X-Forwarded-Host, and X-Forwarded-Proto: https; use a loopback proxy to set
these if necessary. A connector in a different container or machine has a
different localhost. Keep connector credentials private and use the Tunnel's
DNS route for the hostname.
Cloudflare Access is a separate, optional authentication layer. Without Access configured, team members open the domain and sign in to Hunt Web directly. The Hunt Web installer does not impose Cloudflare email rules or require a Cloudflare administrator login. See Cloudflare's Access application guide when configuring that additional layer.
Keep private pages and APIs out of proxy caches. Test login, uploads, Hermes technical messages, and streaming through the enabled WAF rules. Adjust a specific rule if a legitimate request is incorrectly blocked. This proxy protects incoming Dashboard traffic; the scanner's outbound target requests still originate from the VPS.
4. Configure Hermes and Create the First Admin
Return to the application directory on the VPS:
cd "$HOME/hunt-web-v2"
./configure.sh
The guided configuration covers:
- Hermes provider and model: configure the selected provider for scanning and chat. Server setup uses the terminal flow without opening a browser window on the VPS.
- Optional tool keys: ProjectDiscovery and Shodan credentials are separate from the model-provider key. Configure them for tools or data sources that require those credentials; unused optional keys can be skipped.
- Initial Admin setup: save the one-time setup code shown in the terminal. It expires after ten minutes. Answer n when asked to start Dashboard setup now, because the next command starts it explicitly.
Start the setup launcher:
./dashboard.sh --setup
Open the matching address in a browser on the client computer:
| Route | Setup page | Normal sign-in page |
|---|---|---|
| Private SSH, with tunnel connected | http://127.0.0.1:3053/setup | http://127.0.0.1:3053/sign-in |
| HTTPS domain | https://dashboard.example.com/setup | https://dashboard.example.com/sign-in |
Enter the setup code and create the first Admin account. There is no default
username or password. If the code expires before setup is completed, use
./configure.sh --setup-code to issue another code and follow its prompts.
After account creation, stop the setup launcher with Ctrl+C on the VPS, then start normal operation:
./dashboard.sh
Sign in using the newly created account. For an Admin on an HTTPS/domain installation, complete the required authenticator setup in Profile → Security before opening scan pages. Add the displayed account to an authenticator app and enter its current six-digit code. These codes are generated by the app; they are not emailed. Save recovery codes privately for use if the authenticator becomes unavailable.
The private loopback route also offers authenticator protection, but does not apply the same mandatory Admin onboarding rule. Create team accounts through Users & Roles, assigning the role and feature permissions each person needs.
5. Keep Hunt Web Running After SSH Logout
Once setup is complete and no Run or Hermes execution is active, stop the foreground launcher. From the same runtime user's SSH session, install and start the user service:
./dashboard.sh install-service
sudo loginctl enable-linger "$(id -u)"
./dashboard.sh start
./dashboard.sh status
The launcher installs and enables an instance-specific systemd user service.
Lingering allows that user's services to run after logout and at boot.
The systemd loginctl manual
explains this behavior. Record the unit name reported by status; use that
name when reading its journal.
For domain access, the HTTPS address remains accessible after the runtime user's SSH session closes. For private access, the service continues running, but each user's SSH forwarding connection must remain open or be reconnected. Starting the service does not automatically resume a paused scan.
6. Check Health and the First Login
Open Health and check the CLI, database, Hermes connection, and required tools. Then test a fresh browser session: sign in, complete MFA where required, open permitted menus, refresh a page, and log out and back in.
Server installs Chromium headless for scanner tools that need browser automation. Greybox Browser's visible login window remains unavailable in Server mode; installing headless Chromium does not provide a visible Browser window on the client computer. Blackbox, Greybox Environment, Hermes continuation, and PDF reports are available when their required components are configured.
A successful login confirms the access path. Health shows component readiness. To check the complete workflow, create a small authorized test Target, prepare its Scope, start a Run, and inspect the saved results and report.
7. Common Setup Issues
| Symptom | What to check |
|---|---|
| SSH forwarding reports an occupied port | Check the client computer for a local Dashboard or another tunnel using the same port. Match the saved origin rather than changing only the browser URL. |
| Setup or login fails through a domain | Check HTTPS, the exact saved origin, and forwarded host/scheme headers. Use the configured domain consistently. |
| An Admin can sign in but scan menus remain unavailable | Complete authenticator onboarding through Profile → Security when prompted. |
| Dependency installation was interrupted | Correct the reported network, disk, or package issue, then rerun the original install command with the same user, paths, and options. |
| Greybox Browser says unavailable in Server mode | This is expected for interactive Browser. Use Greybox Environment here, or the Desktop installation for visible Browser login. |
| Service fails after logout or reboot | Check ./dashboard.sh status, the reported unit's journal, and user-service lingering. |
| Domain returns 502 | Check the Dashboard service, local upstream, and proxy/connector logs before changing access rules. |
For Cloudflare Tunnel specifically, a 502 stating that it cannot reach the origin means the connector cannot reach the configured local service; it does not by itself show a WAF block. Cloudflare's troubleshooting guide explains how to distinguish these failures.
Keep SSH available for service inspection and recovery. On an HTTPS-bound
installation, forwarding port 3053 to an HTTP localhost address is not a
transparent replacement for domain login: the saved origin and secure cookies
still apply. Plan an HTTPS recovery path that preserves that hostname and TLS.
Keep private backups of application data and deployment configuration,
including proxy/TLS and any Tunnel settings. Use the packaged docs/operations.md
for maintenance and backup procedures. Continue with
Hunt Web's scanning workflow, or see the
Linux Desktop installation guide for
interactive Greybox Browser.