Application Infrastructure Azure

Websurfx on Ubuntu 24.04 on Azure User Guide

| Product: Websurfx Privacy Metasearch Engine on Ubuntu 24.04 LTS on Azure

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), aggregates and de-duplicates the results, and returns them without storing your search history, setting tracking cookies or building an advertising profile. The cloudimg image compiles Websurfx from a pinned upstream release into a single hardened binary, runs it as a non-root websurfx systemd service bound to loopback, backs it with an on-box Redis result cache, and fronts it with an nginx reverse proxy that 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. Backed by 24/7 cloudimg support.

What is included:

  • 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; :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 (the upstream hybrid cache: Redis first, in-process memory fallback) so repeat searches are fast, never reachable off the VM
  • 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 cloudimg 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 cloudimg image places no source-distribution obligation on you.

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point; Websurfx is light on resources at runtime. NSG inbound: 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 the Marketplace for Websurfx by cloudimg, 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 Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name websurfx \
  --image <marketplace-image-urn> \
  --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.

The websurfx, nginx and redis-server services reporting active, the loopback Websurfx listener on 127.0.0.1:8080 and Redis on 127.0.0.1:6379 behind nginx on 443, and the pinned Websurfx release binary

Step 5 - Retrieve your password

nginx protects Websurfx with HTTP Basic Auth over TLS. The username is admin and 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.

The pinned Websurfx binary, the per-VM credentials file with the generated admin password and HTTPS URL, and the bcrypt websurfx.htpasswd entry proving no plaintext password ships

Step 6 - Confirm the health endpoint

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

curl -s http://localhost/healthz

It returns ok. This endpoint never requires authentication, so it is safe 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 reads the per-VM password from the credentials file and proves the round-trip - unauthenticated 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", [])))'

It prints 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.

The HTTP Basic Auth round-trip over TLS returning 401 unauthenticated and 200 with the per-VM password, followed by an authenticated JSON search returning the aggregated result count

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 per Maintenance). It 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.

The Websurfx search home page behind the TLS plus Basic Auth gate, showing the central search box and the clean, distraction-free interface

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.

A Websurfx results page for a sample query showing aggregated, de-duplicated results with per-result engine attribution

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 can keep their own settings.

The Websurfx Settings page showing the general, engines and other preference tabs for tailoring the instance

Step 11 - Review the About page

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

The Websurfx About page describing the privacy-respecting metasearch engine and linking to the project documentation

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 repoint Websurfx at a different set of engines or change the theme, edit config.lua and run sudo systemctl restart websurfx.

The Websurfx config.lua key values binding it to loopback with the Redis cache URL and safe-search level, and Redis answering PONG on loopback

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. cloudimg 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 cloudimg with 24/7 support. For help deploying or operating Websurfx on Azure, contact cloudimg support through the Azure Marketplace listing.