E2guardian
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. A refused request returns a clear block page, and every transaction is written to a structured access log, so outbound browsing is both governed and auditable.
This SecureAnyCloud image builds E2guardian 5.5.9r from upstream source and runs it as the e2guardian.service systemd unit on port 8080. Ubuntu's own archive still carries the 5.3.5 branch, so building from upstream keeps the appliance on a current filtering engine.
What you get:
- E2guardian 5.5.9r (GPL-2.0) built from a sha256-pinned upstream source tarball
e2guardian.servicerunning the filtering proxy on port8080e2guardian-firewall.service, a fail-closed nftables source allowlist- A working, self-demonstrating filter policy, so you can prove filtering on first boot
- A structured access log at
/var/log/e2guardian/access.log e2guardian-firstboot.servicefor 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, patched at build time, with unattended security upgrades enabled
- 24/7 SecureAnyCloud support with a 24h response SLA
Standalone, with 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.
Never an open relay. 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 the allowlist cannot be applied, the proxy does not start at all. Scope your Azure network security group to the same client range as a second layer.
No TLS interception, so no certificate authority key exists. E2guardian can act as a man in the middle to inspect HTTPS payloads, but that 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. This appliance therefore ships with interception off and no CA material at build time or first boot. HTTPS is still filtered by the hostname in the CONNECT request, checked against your site lists.
No login and 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 to find. You administer it over your own key-based SSH.
Prerequisites
You need 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 want to retain a long browsing history locally rather than forward it to a SIEM.
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 fromInternetorAny. An open proxy is found and abused within hours.
Option B: Azure CLI
Run the commands below to create the network and the VM. The rule that matters is allow-proxy-clients, which is scoped to a client CIDR and never to Internet.
RG="e2guardian-prod"; LOCATION="eastus"; VM_NAME="e2guardian-01" IMAGE_URN="sac1647283583153:e2guardian-ubuntu-24-04:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:e2guardian-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--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 StandardConnect 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.
Verify the proxy and its access control are running
Confirm that both units are 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"Expect both units to report active, a listening socket on 0.0.0.0:8080 for the proxy, admin SSH on 0.0.0.0:22, and the version e2guardian 5.5.9r.
Prove that filtering actually works
A running service does not prove that a filtering proxy filters, and neither does a status code, because a block page and a real page can both return successfully. Instead, compare 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, 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 '<title>[^<]*</title>' 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 (<title>Example Domain</title>). 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 filter doing its job. Expected output:
ALLOWED example.com -> <title>Example Domain</title> BLOCKED example.org -> <title>E2Guardian - Access Denied</title>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 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 '<title>[^<]*</title>' 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, and the unauthorised address is dropped. To serve clients from a range outside RFC1918, add it to the e2g_allowed set in /etc/e2guardian/sac-firewall.nft and run sudo systemctl restart e2guardian-firewall, and widen your NSG rule to match.
Read the access log
Review the access log. It records every request, allowed or denied, and denied entries carry the reason and the list that matched.
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.
Read this VM's instance note
Read the root-only note that the first-boot service wrote. It describes 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 by root:root with mode 0600. It states that the appliance has no login and no bootstrap credential, and it records the private proxy endpoint. No public proxy endpoint is advertised, because clients should always reach the proxy over your own network.
Set your own filtering policy
Locate the block list. It is a plain text file with one domain per line, and 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 and remove the example.org demo line when you no longer need it. Then 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). You can populate them 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.
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"When you run this 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, which confirms the client goes 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 address:
proxyip = 10.60.1.20 proxyport = 3128Then 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 '<title>[^<]*</title>'Do not skip that last check. If the upstream address is wrong or unreachable, systemctl still reports e2guardian as active while every request through it returns nothing. Always confirm that a real page comes back after you change proxyip. If it does not, remove the two lines and restart to return to standalone mode.
Restrict Squid's own ACLs to the same client range. Two proxies mean two access control lists, and the weaker one sets your real exposure.
Managing the service
sudo systemctl status e2guardian
sudo systemctl reload e2guardian
sudo systemctl restart e2guardian
sudo journalctl -u e2guardian -n 50 --no-pagerUse reload after a policy edit: it re-reads the lists without dropping connections. Stopping e2guardian-firewall also stops 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 SecureAnyCloud 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/sac-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/sac/ GPL-2 license, written offer and corresponding source
Persistence, first boot and updates
On each VM's first boot, e2guardian-firstboot.service does the following:
- Resolves this machine's own address and records it as a
checkipentry, 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.
- 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 SecureAnyCloud image rather than through apt.
Security Recommendations
- Never expose port
8080to 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_allowednftables 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.orgdemo entry once your own policy is in place.
Support
24/7 SecureAnyCloud support with a 24h response SLA is included with this image. Contact sales@secureanycloud.com.
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/sac/e2guardian-5.5.9r-complete-source.tar.gz, alongside the license 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.
Deploy on Azure
Launch E2guardian 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
Overview
E2guardian is a mature, open source web content filtering proxy. It sits between your users and the internet and applies URL, domain, phrase and content policy to every request, returning a clear block page when a request is refused. It runs as a headless daemon configured through /etc/e2guardian/, with no web console.
This SecureAnyCloud AWS Marketplace image builds E2guardian 5.5.9r from a sha256-pinned upstream source tarball (GPL 2.0) rather than the distribution archive package, which is two minor series behind. It runs standalone, connecting directly to origin sites, so there is no second proxy to deploy. If you already run a Squid caching proxy, you can chain to it with two configuration lines.
What you get:
- E2guardian 5.5.9r built from pinned upstream source and run under systemd (
e2guardian.service) as the unprivilegede2guardianuser, listening on port 8080 e2guardian-firewall.service, a fail-closed nftables source allowlist (loopback and RFC1918 only). The proxyRequires=it, so it never starts without access control- A documented, self-demonstrating local block list seeded with one IANA reserved documentation domain (
example.org), so you can prove filtering works with one command and then add your own policy - The GPL 2.0 corresponding source and a written offer, shipped on the image at
/usr/share/doc/sac/ - A structured access log at
/var/log/e2guardian/access.log, ready to forward to your SIEM - No product login and no bootstrap password: you administer it over your own key-based SSH
Never an open relay. An exposed proxy is one of the most abused assets on the internet. E2guardian itself has no source-address allowlist, so this image ships one. e2guardian-firewall.service installs an nftables table that accepts the proxy port 8080 only from loopback and RFC1918 client networks and drops every other source. e2guardian.service declares Requires=e2guardian-firewall.service, so if the allowlist cannot be applied, the proxy does not start at all. The appliance fails closed rather than opening a relay. Scope your AWS security group to your own client subnet as the mandatory second layer.
No TLS interception, no CA key. E2guardian can perform SSL interception, which would require a certificate authority key. This image deliberately does not: enablessl is off and /etc/e2guardian/private is empty. No CA certificate or private key exists anywhere in the image or on your instance, so there is no shared interception authority to leak. HTTPS is still filtered by CONNECT hostname against the site lists.
Connecting to your instance
This is a headless network service with no web console. Administer it over SSH as the default login user for your operating system variant.
OS variant SSH login user
Ubuntu 24.04 ubuntu
Connect with your EC2 key pair, replacing the key file and address with your own:
ssh -i <your-key>.pem ubuntu@<public-ip>On login, the message of the day summarises the proxy endpoint, the access-control posture and the commands below.
Security group
E2guardian listens on TCP 8080. In the instance's security group:
- Allow TCP 22 inbound from your administration network only, for SSH.
- Allow TCP 8080 inbound only from your trusted client subnets, the networks whose users you want to filter.
Never open port 8080 to 0.0.0.0/0. An internet-reachable proxy is abused within hours. The nftables allowlist on the instance already drops any source outside loopback and RFC1918, but the security group is your first and most important layer. Keep it scoped to your own clients:
aws ec2 authorize-security-group-ingress \
--group-id <your-security-group-id> \
--protocol tcp --port 8080 \
--cidr <your-client-subnet-cidr>Prove filtering works
The image ships a self-demonstrating policy: example.org (IANA's reserved documentation domain) is blocked, and everything else is allowed. SSH in and run the two commands below. A permitted site is fetched through the proxy and returns the real page:
curl -fsS -m 20 --retry 3 --retry-connrefused -x http://127.0.0.1:8080 http://example.com/ \
| grep -qi "Example Domain" \
&& echo "ALLOWED-OK: permitted URL served through the proxy"A banned site is refused with E2guardian's own Access Denied block page, with the real content withheld:
curl -s -m 20 --retry 3 --retry-connrefused -x http://127.0.0.1:8080 http://example.org/ \
| grep -qi "Access Denied" \
&& echo "BLOCKED-OK: banned URL refused with the E2guardian block page"Every request is written to the access log, so the block is auditable:
tail -n 5 /var/log/e2guardian/access.logConfirm it is not an open relay
The proxy is bound to all interfaces, but the fail-closed nftables allowlist accepts it only from loopback and RFC1918 sources. Confirm that the service is up and coupled to its access-control unit:
systemctl is-active e2guardian e2guardian-firewall \
&& systemctl show -p Requires --value e2guardian | grep -q e2guardian-firewall.service \
&& echo "OK: proxy active and Requires the source allowlist (fails closed without it)"Because e2guardian.service requires e2guardian-firewall.service, the proxy does not start if the allowlist fails to apply. It can never come up as an open relay.
Add your own filtering policy
Your block list lives in the filter group's list directory. The per-instance info file records the exact path:
cat /root/e2guardian-info.txtTo block your own domains, add one per line to localbannedsitelist and reload. A bare domain also blocks its subdomains. Substitute your real domains in the example below, and remove the demo example.org entry when you are ready:
echo '<your-domain>' | sudo tee -a /etc/e2guardian/lists/example.group/localbannedsitelist
sudo systemctl reload e2guardianE2guardian also ships upstream category, URL and phrase lists under /etc/e2guardian/lists/ and filter-group configuration in /etc/e2guardian/e2guardianf1.conf. See the E2guardian documentation for the full policy language.
Point clients at the proxy
Set the HTTP and HTTPS proxy on your client machines (or in your DHCP, group policy or PAC file) to the instance's private address on port 8080. For a quick test from a permitted client, run:
export http_proxy=http://<instance-private-ip>:8080
export https_proxy=http://<instance-private-ip>:8080 curl -I https://example.net/Chain to an existing Squid (optional)
This image runs standalone by default. If you already operate a Squid caching proxy and want E2guardian to filter in front of it, set proxyip and proxyport in /etc/e2guardian/e2guardian.conf to your Squid. Then run sudo systemctl restart e2guardian.
Licensing
E2guardian is distributed under the GNU General Public License version 2. The complete corresponding source for the binaries in this image and a written offer are shipped on the instance at /usr/share/doc/sac/. SecureAnyCloud is not affiliated with or endorsed by the E2guardian project. "E2guardian" is used nominatively to identify the software.
Support
SecureAnyCloud provides 24/7 technical support for this image via email (sales@secureanycloud.com) and live chat. Our engineers can help with scoping client access, restricting the proxy port to trusted subnets, building filtering policy, chaining to an upstream Squid, forwarding the access log to your SIEM, and version upgrades.
Deploy on AWS
Launch E2guardian Web Content Filtering Proxy with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com