Ef
Networking Azure

E2guardian Filtering Proxy on Ubuntu 24.04 on Azure User Guide

| Product: E2guardian on Ubuntu 24.04 LTS on Azure

Overview

E2guardian is a mature open source web content filtering proxy. It sits between your users and the internet and applies policy to every request, filtering by domain, URL, file extension, MIME type and weighted phrase content, and returning a clear block page when a request is refused rather than failing silently. Every transaction is written to a structured access log, so outbound browsing is both governed and auditable.

The cloudimg image builds E2guardian 5.5.9r from upstream source and runs it as the e2guardian.service systemd unit, listening on port 8080. Ubuntu's own archive still carries the 5.3.5 branch, so building from upstream is what keeps this appliance on a current filtering engine.

It runs standalone. There is no Squid to deploy. E2guardian 5.x connects directly to origin sites when no upstream proxy is configured, so this image is a complete filtering proxy on its own: one daemon, one set of access rules. If you already run Squid you can chain to it with two configuration lines, shown later in this guide.

It is not an open relay, and that is enforced rather than documented. An exposed proxy is one of the most abused assets on the internet. E2guardian has no source address allowlist of its own and binds all interfaces by default, so this image ships e2guardian-firewall.service, an nftables allowlist that accepts port 8080 only from loopback and RFC1918 client networks and drops every other source. e2guardian.service declares Requires=e2guardian-firewall.service, so if that allowlist cannot be applied the proxy does not start at all. Scope your Azure network security group to the same client range as the second layer.

No TLS interception, so no certificate authority key exists. E2guardian can be run as a man in the middle to inspect HTTPS payloads, which requires a certificate authority certificate and private key. A CA key baked into a marketplace image would be shared by every customer of that image, so this appliance ships with interception off and no CA material whatsoever, at build time or first boot. HTTPS is still filtered, by the hostname in the CONNECT request against your site lists.

No login, no bootstrap password. E2guardian is a headless daemon with no web console and no product account, so there is nothing to sign in to and no default credential exists to be found. Administration is over your own key based SSH.

What is included:

  • E2guardian 5.5.9r (GPL-2.0) built from a sha256 pinned upstream source tarball
  • e2guardian.service running the filtering proxy on port 8080
  • e2guardian-firewall.service, a fail closed nftables source allowlist
  • A working, self demonstrating filter policy so you can prove filtering on first boot
  • Structured access log at /var/log/e2guardian/access.log
  • e2guardian-firstboot.service for per VM proxy facts and request loop prevention
  • The complete corresponding source and GPL-2 written offer shipped on the image
  • Ubuntu 24.04 LTS base, fully patched, unattended security upgrades enabled
  • 24/7 cloudimg support, 24h response SLA

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet with a subnet that your client machines sit on. E2guardian is efficient; Standard_B2s (2 vCPU, 4 GB RAM) comfortably handles a small to medium user population. Access logs live on the OS disk, so expand the disk if you intend to retain a long browsing history locally rather than forwarding it to a SIEM.

Step 1: Deploy the Virtual Machine

Option A: Azure Portal

Search the Marketplace for E2guardian Filtering Proxy on Ubuntu 24.04, choose your VM size, and provide your SSH public key. Attach a network security group that allows:

  • TCP 22 (admin SSH) from your management network only.
  • TCP 8080 (the proxy) from your client subnet only. Never from Internet or Any. An open proxy is found and abused within hours.

Option B: Azure CLI

The rule that matters here is allow-proxy-clients: it is scoped to a client CIDR, never to Internet.

RG="e2guardian-prod"; LOCATION="eastus"; VM_NAME="e2guardian-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/e2guardian-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name e2g-vnet --address-prefix 10.60.0.0/16 --subnet-name e2g-subnet --subnet-prefix 10.60.1.0/24
az network nsg create -g "$RG" --name e2g-nsg
az network nsg rule create -g "$RG" --nsg-name e2g-nsg --name allow-admin-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name e2g-nsg --name allow-proxy-clients --priority 110 \
  --source-address-prefixes "10.60.1.0/24" --destination-port-ranges 8080 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name e2g-vnet --subnet e2g-subnet --nsg e2g-nsg --public-ip-sku Standard

Step 2: Connect via SSH

ssh azureuser@<vm-ip>

Find the public IP with az vm show -d -g e2guardian-prod -n e2guardian-01 --query publicIps -o tsv.

Step 3: Verify the proxy and its access control are running

Both units must be active. The proxy is deliberately coupled to the allowlist, so a healthy proxy implies a healthy allowlist.

sudo systemctl start e2guardian-firewall e2guardian 2>/dev/null || true
sleep 3
sudo systemctl is-active e2guardian
sudo systemctl is-active e2guardian-firewall
ss -tln | grep -E ':8080 |:22 ' || true
e2guardian -v | head -1
echo "e2guardian verified"

You should see both units reporting active, a listening socket on 0.0.0.0:8080 for the proxy, your admin SSH on 0.0.0.0:22, and e2guardian 5.5.9r.

Terminal showing the e2guardian and e2guardian-firewall services both active, the proxy listening on port 8080 alongside admin SSH on port 22, and E2guardian reporting version 5.5.9r

Step 4: Prove that filtering actually works

This is the important step. A running service proves nothing about a filtering proxy, and a status code proves nothing either, because a block page and a real page can both be returned successfully. The check below compares the content returned for a permitted site against the content returned for a blocked one.

The image ships exactly one demo block entry: example.org, which is IANA's reserved documentation domain, so blocking it affects no real service. example.com is not blocked, and both serve the same page when unfiltered, which makes them a clean pair for the test.

printf 'ALLOWED  example.com -> '
curl -s -m 20 -x http://127.0.0.1:8080 http://example.com/ | grep -o '<h1>[^<]*</h1>'
printf 'BLOCKED  example.org -> '
curl -s -m 20 -x http://127.0.0.1:8080 http://example.org/ | grep -o '<title>[^<]*</title>'
echo "filtering verified"

The permitted request returns the real page (<h1>Example Domain</h1>). The blocked request returns E2guardian's own block page (<title>E2Guardian - Access Denied</title>) and the real page content is absent entirely. That difference is the product doing its job.

ALLOWED  example.com -> <h1>Example Domain</h1>
BLOCKED  example.org -> <title>E2Guardian - Access Denied</title>

Terminal showing a permitted URL returning the real page heading through the proxy while a banned URL returns the E2Guardian Access Denied block page instead, proving content filtering is genuinely enforced

Step 5: Confirm the appliance is not an open relay

The allowlist accepts loopback and RFC1918 sources and drops everything else. You can exercise the real rule with a genuine foreign source address: 203.0.113.7 is from TEST-NET-3, a range reserved for documentation, so it can never collide with your own network.

The first request is the positive control. If a permitted source could not relay either, a refusal would prove nothing.

sudo nft list table inet e2guardian
H=$(hostname -I | awk '{print $1}')
sudo ip addr add 203.0.113.7/32 dev lo 2>/dev/null || true
printf 'permitted source %s -> ' "$H"
curl -s -m 15 --interface "$H" -x http://$H:8080 http://example.com/ | grep -o '<h1>[^<]*</h1>'
printf 'unauthorised source 203.0.113.7 -> '
curl -s -m 8 --interface 203.0.113.7 -x http://$H:8080 http://example.com/ >/dev/null 2>&1 && echo "RELAYED" || echo "refused by the source allowlist"
sudo ip addr del 203.0.113.7/32 dev lo 2>/dev/null || true
echo "relay refusal verified"

The permitted private address relays successfully; the unauthorised address is dropped. To serve clients from a range outside RFC1918, add it to the e2g_allowed set in /etc/e2guardian/cloudimg-firewall.nft and run sudo systemctl restart e2guardian-firewall, and widen your NSG rule to match.

Terminal showing the nftables allowlist rules and a relay test in which a permitted private source successfully proxies a request while an unauthorised source address is refused

Step 6: Read the access log

Every request, allowed or denied, is recorded. Denied entries carry the reason and the list that matched, which is what makes the appliance auditable.

sudo tail -n 3 /var/log/e2guardian/access.log
echo "access log verified"

Each line records the timestamp, client address, URL, method, status and, for a denial, the reason such as *DENIED* Blocked site (local): example.org. Forward this file to your SIEM with any standard log shipper.

Terminal showing the E2guardian access log with an allowed request recorded alongside a denied request carrying the DENIED reason and the list that matched

Step 7: Read this VM's instance note

The first boot service wrote a root only note describing this VM's proxy endpoint, the access control in force, and the TLS posture.

sudo cat /root/e2guardian-info.txt
echo "instance note verified"

The note is owned root:root with mode 0600. It states plainly that the appliance has no login and no bootstrap credential, and records the private proxy endpoint. No public proxy endpoint is advertised, because clients should always reach the proxy over your own network.

Step 8: Set your own filtering policy

The block list is a plain text file, one domain per line. A bare domain also covers its subdomains.

E2G_LISTS=$(sed -nE 's/^[[:space:]]*\.Define[[:space:]]+LISTDIR[[:space:]]*<([^>]+)>.*/\1/p' /etc/e2guardian/e2guardianf1.conf | head -1)
echo "your block list is at $E2G_LISTS/localbannedsitelist"
sudo grep -v '^#' "$E2G_LISTS/localbannedsitelist" | grep -v '^$'
echo "block list located"

Add your own domains to that file, remove the example.org demo line when you no longer need it, and apply the change:

sudo systemctl reload e2guardian
echo "policy reloaded"

E2guardian also ships upstream's category and weighted phrase lists in the same directory (bannedsitelist, bannedurllist, weightedphraselist and others), which you can populate with a commercial or community blocklist feed. The localbannedsitelist used above is upstream's dedicated file for local administrator additions, so your entries stay separate from any feed you import.

Step 9: Point a client at the proxy

From a machine on your client subnet, set the standard proxy environment variables, or configure the proxy in your browser or operating system network settings.

PROXY=$(sudo sed -n 's/^E2GUARDIAN_PROXY_URL=//p' /root/e2guardian-info.txt)
echo "using proxy $PROXY"
export http_proxy="$PROXY"
export https_proxy="$PROXY"
curl -s -o /dev/null -w 'allowed site  -> HTTP %{http_code}\n' http://example.com/
curl -s http://example.org/ | grep -o '<title>[^<]*</title>'
echo "client proxy configuration verified"

Run from a client machine, replace the first line with your proxy's private address. The allowed site returns HTTP 200 and the blocked site returns the E2Guardian block page, confirming the client is genuinely going through the filter rather than straight out to the internet.

Use the private address from the instance note. HTTPS requests are filtered by the hostname in the CONNECT request, so domain policy applies to HTTPS as well as HTTP, without any interception of the encrypted payload.

Optional: chain to an existing Squid deployment

If you already run Squid and want E2guardian to filter in front of it, add the upstream proxy directives to /etc/e2guardian/e2guardian.conf and restart. E2guardian then forwards permitted requests to Squid instead of fetching them directly.

Edit the file with sudo nano /etc/e2guardian/e2guardian.conf and add these two lines, substituting your Squid host's real address:

proxyip = 10.60.1.20
proxyport = 3128

Then apply and confirm the proxy still serves traffic:

sudo systemctl restart e2guardian
sleep 3
curl -s -m 20 -x http://127.0.0.1:8080 http://example.com/ | grep -o '<h1>[^<]*</h1>'

That last check matters. If the upstream address is wrong or unreachable, systemctl will still report e2guardian as active while every request through it returns nothing, so always confirm a real page comes back after changing proxyip. If it does not, remove the two lines and restart to return to standalone mode.

Harden Squid's own ACLs to the same client range. Two proxies mean two access control lists, and the weaker of the pair is the one that matters.

Managing the service

sudo systemctl status e2guardian
sudo systemctl reload e2guardian
sudo systemctl restart e2guardian
sudo journalctl -u e2guardian -n 50 --no-pager

reload re-reads the lists without dropping connections, which is what you want after a policy edit. Note that stopping e2guardian-firewall will also stop the proxy, because the proxy requires it.

Server Components

Component Version Purpose
E2guardian 5.5.9r Web content filtering proxy
e2guardian.service systemd Runs the proxy in the foreground under supervision
e2guardian-firewall.service systemd Applies the nftables source allowlist, fail closed
e2guardian-firstboot.service systemd Per VM proxy facts and loop prevention address
nftables Ubuntu 24.04 Enforces the proxy source allowlist
Ubuntu 24.04 LTS Base operating system

Filesystem Layout

Path Purpose
/etc/e2guardian/e2guardian.conf Main configuration, including the cloudimg policy block
/etc/e2guardian/e2guardianf1.conf Filter group configuration and list directory definition
/etc/e2guardian/lists/example.group/ The filter group's lists, including localbannedsitelist
/etc/e2guardian/cloudimg-firewall.nft The nftables source allowlist
/etc/e2guardian/private/ Empty by design; no CA certificate or key is ever created
/var/log/e2guardian/access.log Structured access log
/root/e2guardian-info.txt Root only per VM instance note
/usr/share/doc/cloudimg/ GPL-2 licence, written offer and corresponding source

Persistence, first boot and updates

On each VM's first boot, e2guardian-firstboot.service resolves this machine's own address and records it as a checkip entry so a client that points the proxy back at itself cannot spin a request loop, writes a fresh empty access log so no build time browsing history is ever present, writes the instance note and MOTD, and re-asserts that no CA material exists. It then marks itself complete and does not run again.

Ubuntu security updates are applied automatically by unattended upgrades. E2guardian itself was built from source at image build time, so new upstream releases arrive through a refreshed cloudimg image rather than through apt.

Security Recommendations

  • Never expose port 8080 to the internet. Keep the NSG rule scoped to your client subnet. The on host allowlist is a safety net, not a substitute for the NSG.
  • Keep the two layers in agreement. If you widen the e2g_allowed nftables set, widen the NSG rule to match, and no further.
  • Leave TLS interception off unless you have a specific mandate for it. Enabling it means generating and distributing a CA private key, and every client that trusts it is exposed if that key leaks. Hostname filtering covers most policy needs without that risk.
  • Restrict admin SSH to your management network, and keep it key based.
  • Forward the access log to a SIEM if browsing records are subject to retention requirements.
  • Review your block lists on a schedule, and remove the shipped example.org demo entry once your own policy is in place.

Support

24/7 cloudimg support with a 24h response SLA is included with this image. Contact support@cloudimg.co.uk.

E2guardian is distributed under the GNU General Public License version 2. The complete corresponding source for the binaries in this image ships on the image at /usr/share/doc/cloudimg/e2guardian-5.5.9r-complete-source.tar.gz, alongside the licence text and a written offer valid for three years. "E2guardian" is used nominatively to identify the software; all product and company names are trademarks of their respective holders.