Deployment guide

Websurfx

Overview

Websurfx is a free, open source, privacy-respecting metasearch engine written in Rust. Instead of profiling you, it forwards your query to several upstream engines (DuckDuckGo, Wikipedia, Brave, Mojeek and Bing on this image) and aggregates and de-duplicates the results. It returns them without storing your search history, setting tracking cookies or building an advertising profile.

The SecureAnyCloud image compiles Websurfx from a pinned upstream release into a single hardened binary and runs it as a non-root websurfx systemd service bound to loopback. An nginx reverse proxy terminates TLS and adds a per-VM HTTP Basic Auth gate, so the instance is never left open as a public search proxy. A unique Basic Auth password and a self-signed TLS certificate are generated on the first boot of every VM.

What you get:

  • Websurfx (pinned upstream release v1.29.9) compiled as a single Rust binary and run as the websurfx systemd service, bound to loopback 127.0.0.1:8080.
  • An nginx reverse proxy terminating TLS on :443 and adding a per-VM HTTP Basic Auth gate (user admin) with a unique password generated on first boot. Port :80 serves the health probe and redirects everything else to HTTPS.
  • A per-VM self-signed TLS certificate generated on first boot (SAN set to the instance public IP).
  • An on-box Redis result cache bound to loopback 127.0.0.1:6379 and never reachable off the VM. It is the upstream hybrid cache, with Redis first and an in-process memory fallback, so repeat searches are fast.
  • The JSON search API enabled (?json=true) alongside the HTML interface, for scripting and integrations.
  • websurfx.service, nginx.service and redis-server.service as systemd units, enabled and active.
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes.
  • 24/7 SecureAnyCloud support.

Websurfx is licensed under the GNU Affero General Public License v3 (AGPL-3.0). If you modify Websurfx and offer the modified version to users over a network, the AGPL requires you to make your modified source available to those users. Running the unmodified SecureAnyCloud image places no source-distribution obligation on you.

Prerequisites

  • An active Azure subscription, an SSH key pair, and a VNet and subnet in the target region.
  • Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point, because Websurfx is light on resources at runtime.
  • NSG inbound rules that allow 22/tcp from your management network, 443/tcp for the web interface, and 80/tcp for the health probe and the HTTPS redirect.

The image ships a self-signed certificate. For production, put your own domain and a CA or Let's Encrypt certificate in front of nginx (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search Azure Marketplace for Websurfx by SecureAnyCloud, and select Create. On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22), HTTPS (443) and HTTP (80). Then select Review + create and Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:websurfx-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name websurfx \
  --image sac1647283583153:websurfx-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name websurfx --port 443 --priority 1010
az vm open-port --resource-group <your-rg> --name websurfx --port 80 --priority 1020

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active websurfx.service nginx.service redis-server.service

All three report active. Websurfx runs as the dedicated non-root websurfx user, bound to the loopback listener 127.0.0.1:8080. nginx fronts it on :443 with TLS and the per-VM HTTP Basic Auth gate, and exposes an unauthenticated /healthz. Redis provides the on-box result cache on loopback 127.0.0.1:6379.

Step 5 - Retrieve your password

nginx protects Websurfx with HTTP Basic Auth over TLS. The username is admin. A unique password is generated on the first boot of your VM and written to a root-only file:

sudo cat /root/websurfx-credentials.txt

This file contains WEBSURFX_USERNAME, WEBSURFX_PASSWORD and the WEBSURFX_URL to open in a browser. The password is stored on disk only as a bcrypt hash in /etc/nginx/websurfx.htpasswd, so no plaintext password ships in the image. Store the password somewhere safe.

Step 6 - Confirm the health endpoint

nginx serves an unauthenticated health endpoint for load balancers and probes:

curl -s http://localhost/healthz

The endpoint returns ok. It never requires authentication, so it is safe to use for an Azure Load Balancer health probe.

Step 7 - Confirm authentication and the JSON search API

Because a password is set on first boot, an unauthenticated request returns HTTP 401, so nobody reaches your instance without the password. The following commands read the per-VM password from the credentials file and prove the round trip. An unauthenticated request is rejected, the correct password authenticates over TLS, and an authenticated JSON search returns aggregated results. The -k flag accepts the self-signed certificate.

PW=$(sudo grep '^WEBSURFX_PASSWORD=' /root/websurfx-credentials.txt | cut -d= -f2-)
echo "unauth : $(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/)"
echo "authed : $(curl -sk -o /dev/null -w '%{http_code}' -u admin:$PW https://127.0.0.1/)" curl -sk -u admin:$PW 'https://127.0.0.1/search?q=privacy&json=true' \
  | python3 -c 'import sys,json; d=json.load(sys.stdin); print("results:", len(d.get("results", [])))'

The output shows unauth : 401, then authed : 200, then a non-zero result count. The ?json=true endpoint is enabled on this image so you can drive Websurfx from scripts and integrations. The same query without it returns the HTML results page.

Step 8 - Sign in and open the search page

Browse to https://<vm-public-ip>/. Your browser warns once about the self-signed certificate. Accept it, or install your own certificate as described under Maintenance.

The browser then prompts for a username and password. Enter admin and the password from Step 5. Websurfx opens on its clean search home, a single search box with no ads, no tracking and no cookies set until you choose to save preferences.

Step 9 - Run a private search

Type a query and press Enter. Websurfx queries the upstream engines in parallel, aggregates and de-duplicates the results, and shows them with per-result engine attribution. Repeat queries are served from the on-box Redis cache for speed. Your query is never logged or tied to a profile.

Step 10 - Tune engines and preferences

Open Settings to tailor the instance. From here you choose the colour scheme and theme, set your safe-search level, and enable or disable any of the upstream engines. Preferences are stored in your browser (or an opt-in cookie), so different users of the same instance keep their own settings.

Step 11 - Review the About page

The About page describes what Websurfx is and links to the project documentation. It helps users of your instance understand the privacy model of the metasearch engine they are using.

Step 12 - Review the configuration and cache

Websurfx's configuration lives at /etc/xdg/websurfx/config.lua, and the on-box Redis cache is bound to loopback:

grep -E 'binding_ip|^port|redis_url|safe_search' /etc/xdg/websurfx/config.lua systemctl is-active redis-server.service redis-cli -h 127.0.0.1 ping

The config binds Websurfx to loopback 127.0.0.1:8080, points the cache at redis://127.0.0.1:6379, and sets the safe-search level. Redis answers PONG on loopback only.

To use a different set of engines or change the theme, edit config.lua and run sudo systemctl restart websurfx.

Maintenance

  • Change the password. Regenerate the Basic Auth file with sudo htpasswd -B /etc/nginx/websurfx.htpasswd admin. Then update /root/websurfx-credentials.txt for your records and reload nginx with sudo systemctl reload nginx.
  • Add engines or change settings. Edit /etc/xdg/websurfx/config.lua (the upstream_search_engines table) and run sudo systemctl restart websurfx.
  • Add TLS for production. Put your own domain in front of nginx and replace the self-signed certificate in /etc/ssl/websurfx/ with one from your CA or Let's Encrypt. Then reload nginx.
  • Updates. Websurfx is pinned to a specific upstream release in this image for reproducibility. SecureAnyCloud publishes refreshed images. For security patches, apply OS updates with sudo apt update && sudo apt upgrade.
  • Cache. The on-box Redis cache holds search results for a short expiry. It is bound to loopback and never exposed off the VM. Flush it any time with redis-cli flushall.

Support

This image is maintained by SecureAnyCloud with 24/7 support. For help deploying or operating Websurfx on Azure, contact SecureAnyCloud support through the Azure Marketplace listing.

Deploy on Azure

Launch Websurfx Privacy Metasearch Engine on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure