E5
Networking AWS

E2guardian 5.5.9r on AWS User Guide

| Product: E2guardian 5.5.9r with Squid on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying E2guardian 5.5.9r with Squid on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other VPN, proxy and remote access servers in the listing are described on the listing's guide hub.

E2guardian is an open-source web content filter. Your clients use it as their HTTP and HTTPS proxy; it checks every request against site, URL, file-type and phrase lists and answers a refused request with a clear block page. Squid sits behind it as the caching upstream: E2guardian forwards every permitted request to Squid, which fetches it from the internet or serves it from its cache. The result is one instance that both governs and accelerates your VPC's outbound web traffic.

On this image E2guardian listens on tcp/8080 and answers only clients inside your VPC's address range, which it reads from the instance metadata on first boot, so it can never be used as an open proxy. Squid listens on the instance's loopback address only.

E2guardian 5.5.9r is compiled by cloudimg from the checksum-pinned upstream release (the Ubuntu archive carries the much older 5.3 branch); the compiler is removed again before the image is captured. Squid 6.14 is the fully patched Ubuntu package.

What is on the image:

  • E2guardian 5.5.9r (e2guardian.service) on tcp/8080, running as the unprivileged e2guardian user
  • Squid 6.14 (squid.service) on 127.0.0.1:3128 only, as E2guardian's caching upstream
  • tcp/8080 for your VPC only: an nftables allow-list (e2guardian-firewall.service) written on first boot from your VPC's CIDR blocks; every other source is dropped
  • No TLS interception: no CA certificate or private key exists on the image or your instance; HTTPS is filtered by host name
  • A demonstration policy: one blocked domain, example.org (IANA's reserved documentation domain), so you can prove filtering in one command
  • No metadata access: neither service can reach the instance metadata service, and Squid refuses to fetch it (or any link-local or loopback address) for a client
  • Helpers: squid-e2guardian-roundtrip.sh (the self-test) and squid-e2guardian-acl (the client allow-list)
  • The firmware-refresh timer (fwupd-refresh) is masked: EC2 has no firmware that LVFS can update
  • The complete E2guardian source and a GPL written offer in /usr/share/doc/cloudimg/

Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3

Security posture

  • Not an open proxy. E2guardian listens on tcp/8080 on every interface, but an nftables table drops every packet to port 8080 whose source is not on /etc/e2guardian/allowed-clients.txt. First boot fills that file with your VPC's IPv4 (and IPv6, if any) CIDR blocks; loopback is always allowed. The listing's default security group opens SSH only, so the proxy is closed until you open tcp/8080 to your own networks.
  • Squid is never exposed. Squid listens on 127.0.0.1:3128 only and accepts requests from the instance itself (E2guardian) only. It refuses to fetch the instance metadata service (169.254.169.254, fd00:ec2::254), any other link-local or loopback address, CONNECT to anything but port 443, and its own cache manager, so no client can use the proxy to reach them.
  • No TLS interception, no CA key. E2guardian can decrypt HTTPS if you give it a certificate authority; this image does not. /etc/e2guardian/private is empty, TLS interception stays off, and HTTPS requests are allowed or refused by host name.
  • No SSRF to instance credentials. e2guardian.service and squid.service both carry an IPAddressDeny rule for the metadata addresses (169.254.169.254, fd00:ec2::254, 168.63.129.16). Only those are blocked: Squid still reaches every internet host. The AMI is registered IMDSv2 only.
  • Least privilege. E2guardian runs as the e2guardian system user with a read-only system and a private /tmp; it can write only its log directory. Squid's workers run as proxy.
  • Fails closed. E2guardian starts only after first boot has written this instance's allow-list and a ready marker, only while the allow-list is loaded, and only with Squid running. A start-up check also refuses to run it with anything in /etc/e2guardian/private, with TLS interception switched on, or with the upstream proxy changed away from the local Squid.
  • No default credential. Neither E2guardian nor Squid has a login on this image: clients are allowed by source address. Administration is over SSH with your key pair (password and root logins are off).
  • Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.
  • Security notes. E2guardian 5.5.9r has no published security advisory. An upstream fix for a crash in the optional header authentication plugin (issue #897) is not yet in a release; the plugin is off on this image, so do not enable it before E2guardian 5.5.10. Squid is the fully patched Ubuntu package (USN-8941-1); the open Squid advisories SQUID-2026:7 and SQUID-2026:8 affect only cache_peer logins and ICAP with external ACL helpers, which this configuration does not use.

Prerequisites

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in
  3. A subnet with outbound HTTP and HTTPS to the internet (a public subnet, or a private subnet with a NAT gateway): Squid fetches pages for your clients

Recommended instance type: m5.large. Squid keeps up to 256 MB of hot objects in memory and 1 GB on disk; give it a larger instance and volume for a busy VPC.

Connecting to your instance

Version Operating system SSH user
E2guardian 5.5.9r with Squid on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  2. Once the subscription is active, choose Launch your software.
  3. Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose E2guardian 5.5.9r with Squid on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  5. Security group: the listing's default group allows SSH (22) only. Restrict SSH to your own IP address. You open the proxy port to your VPC in Step 6.
  6. Choose the VPC whose clients will use the proxy and a subnet with outbound internet access, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.

Option B: AWS CLI

Run this on your own workstation. It creates a security group that allows SSH from your management address and the proxy port from the VPC, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR ranges with your own:

SG=$(aws ec2 create-security-group --group-name e2guardian-squid \
  --description "E2guardian filtering proxy with Squid cache" --vpc-id vpc-0123456789abcdef0 \
  --query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 8080 --cidr <your-vpc-cidr>
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type m5.large \
  --key-name my-key-pair \
  --security-group-ids "$SG" \
  --subnet-id subnet-0123456789abcdef0 \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=e2guardian-squid}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required.

Step 2: Connect and read the instance details

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>

First boot finishes within a minute of launch. It writes the client allow-list from your VPC's CIDR blocks, adds the instance's private address to E2guardian's loop protection, starts Squid and E2guardian and checks that they answer. The details are in /root/squid-e2guardian-info.txt, readable only by root. Nothing in it is secret, because the proxy has no password:

sudo cat /root/squid-e2guardian-info.txt
# E2guardian 5.5.9r with Squid on Ubuntu 24.04 - generated on first boot by squid-e2guardian-firstboot.service.
# This proxy has NO login and NO password: clients are allowed by source address only (allowed-clients.txt).
# Nothing here is secret; the file is root-only because it describes this instance's network layout.

PROXY_URL=http://172.31.85.47:8080
PROXY_PRIVATE_IP=172.31.85.47
PROXY_PORT=8080
ALLOWED_CLIENTS=172.31.0.0/16 (+ loopback; /etc/e2guardian/allowed-clients.txt)
FILTER=e2guardian 5.5.9r (tcp/8080; /etc/e2guardian/e2guardian.conf)
CACHE=squid (127.0.0.1:3128 only; /etc/squid/squid.conf)
TLS_INTERCEPTION=off (no CA certificate or key exists; HTTPS is filtered by host name)
SELF_TEST=sudo /usr/local/sbin/squid-e2guardian-roundtrip.sh
GUIDE=https://www.cloudimg.co.uk/guides/e2guardian-5-5-9r-on-ubuntu-24-04-aws/

PROXY_URL is the address your clients use. Your values differ.

Step 3: Confirm the proxy is running

Squid, the allow-list and E2guardian are active. E2guardian owns tcp/8080 on every interface; Squid owns 127.0.0.1:3128 only:

systemctl is-active squid.service e2guardian-firewall.service e2guardian.service
e2guardian -v | head -1
squid -v | head -1
sudo ss -Htlnp '( sport = :8080 or sport = :3128 )' | awk '{print $4}'
active
active
active
e2guardian 5.5.9r
Squid Cache: Version 6.14
0.0.0.0:8080
127.0.0.1:3128

Step 4: Run the self-test

The shipped self-test checks the whole proxy from the instance itself: the services and listeners, the allow-list, a permitted page served through E2guardian and fetched by Squid, the blocked domain refused over HTTP and HTTPS, the metadata service and loopback addresses refused through the proxy, a repeat fetch served from Squid's cache, no CA material, the access log, and no metadata access from inside either service:

sudo /usr/local/sbin/squid-e2guardian-roundtrip.sh
ok: e2guardian (user e2guardian) on tcp/8080; Squid on 127.0.0.1:3128 only
ok: tcp/8080 allow-list loaded: 127.0.0.0/8 172.31.0.0/16 (every other source dropped)
ok: permitted URL served through e2guardian and fetched by Squid (control: the blocked domain is reachable directly)
ok: example.org blocked over HTTP (block page, real content withheld) and HTTPS CONNECT (control: https://example.com/ tunnels)
ok: metadata service (GET + IMDSv2 token PUT) and loopback destinations refused through the proxy (control: internet URLs above)
ok: a repeat fetch is served from Squid's cache (TCP_*HIT)
ok: no TLS interception and no CA material
ok: the blocked request is recorded in /var/log/e2guardian/access.log
ok: metadata: 169.254.169.254 is unreachable from inside e2guardian and Squid
ROUNDTRIP_OK

Step 5: See filtering and caching work

A permitted page comes back through the proxy; the demonstration domain example.org gets E2guardian's block page instead; an HTTPS page tunnels (200) while HTTPS to the blocked domain is refused (000: the tunnel is never opened):

curl -s -x http://127.0.0.1:8080 http://example.com/ | grep -o '<title>.*</title>'
curl -s -x http://127.0.0.1:8080 http://example.org/ | grep -o '<title>.*</title>'
curl -s -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:8080 https://example.com/
curl -s -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:8080 https://example.org/ || true
<title>Example Domain</title>
<title>E2Guardian - Access Denied</title>
200
000

Every permitted request reaches Squid, which records whether it was served from its cache (TCP_MEM_HIT, TCP_HIT) or fetched (TCP_MISS); E2guardian records every request, allowed or denied, with the client address:

sudo grep -a 'example.com' /var/log/squid/access.log | tail -n 2 | awk '{print $4, $6, $7}'
sudo grep -ac 'DENIED' /var/log/e2guardian/access.log
TCP_MEM_HIT/200 GET http://example.com/
TCP_TUNNEL/200 CONNECT example.com:443
9

Step 6: Serve your VPC

The allow-list already contains your VPC's CIDR blocks; the security group decides whether proxy traffic reaches the instance at all. Open tcp/8080 to your VPC (or to the subnets of your clients) in the instance's security group, never to 0.0.0.0/0:

aws ec2 authorize-security-group-ingress --group-id <your-sg> --protocol tcp --port 8080 --cidr <your-vpc-cidr>

Then point clients at PROXY_URL from Step 2. For a Linux client, set the standard proxy variables (most command-line tools and package managers honour them); browsers and desktops take the same address in their proxy settings, or through a PAC file or group policy:

export http_proxy=http://<instance-private-ip>:8080 https_proxy=http://<instance-private-ip>:8080
export no_proxy=169.254.169.254,localhost,127.0.0.1
curl -I https://example.com/

Keep the metadata address in no_proxy: the proxy refuses to fetch it for a client, so a client's own metadata requests must go direct.

A client outside the allow-list cannot even open a connection, even if the security group lets its packets in: its packets are dropped and counted. The current list and the drop counter:

sudo grep -v '^#' /etc/e2guardian/allowed-clients.txt
sudo squid-e2guardian-acl show
172.31.0.0/16
table inet cloudimg_e2g {
    set allow4 {
        type ipv4_addr
        flags interval
        elements = { 127.0.0.0/8, 172.31.0.0/16 }
    }

    set allow6 {
        type ipv6_addr
        flags interval
        elements = { ::1 }
    }

    chain input {
        type filter hook input priority filter - 10; policy accept;
        iifname "lo" accept
        tcp dport 8080 ip saddr @allow4 accept
        tcp dport 8080 ip6 saddr @allow6 accept
        tcp dport 8080 counter packets 0 bytes 0 drop
    }
}

Step 7: Allow more client networks

Clients outside the VPC range (a VPN pool, a peered VPC, an on-premises network over Direct Connect) need their range on the allow-list. Add one CIDR per line and apply it; the change is atomic and needs no restart:

echo '10.8.0.0/24' | sudo tee -a /etc/e2guardian/allowed-clients.txt
sudo squid-e2guardian-acl apply

squid-e2guardian-acl refuses 0.0.0.0/0 and ::/0, which would turn the instance into an open proxy. Remember to allow the same range in the security group. If you start or reload nftables.service (which flushes every firewall table), the allow-list is applied again automatically.

Step 8: Write your filtering policy

E2guardian's policy lives in /etc/e2guardian/: the main settings in e2guardian.conf, the filter group in e2guardianf1.conf, and the lists in lists/example.group/. Your own blocked domains go in localbannedsitelist, one per line (a domain also blocks its subdomains). The image ships one entry:

sudo grep -v '^#' /etc/e2guardian/lists/example.group/localbannedsitelist | grep .
example.org

Replace it with your own domains and restart E2guardian:

sudo nano /etc/e2guardian/lists/example.group/localbannedsitelist
sudo systemctl restart e2guardian

The same directory holds the other upstream lists (bannedsitelist, exceptionsitelist, bannedurllist, bannedextensionlist, phrase lists and more); E2guardian's documentation at https://github.com/e2guardian/e2guardian/wiki describes each. Squid's caching settings are in /etc/squid/squid.conf; after a change run sudo squid -k parse and then sudo systemctl restart squid.

Step 9: HTTPS without interception

E2guardian decides HTTPS requests by host name from the CONNECT request, so blocking a domain also blocks it over HTTPS, without decrypting anything. No certificate authority exists on the image, and TLS interception is off:

sudo ls -A /etc/e2guardian/private | wc -l
grep -cE '^[[:space:]]*enablessl' /etc/e2guardian/e2guardian.conf || true
0
0

Page-level filtering of HTTPS (phrases, file types inside encrypted pages) needs TLS interception with your own certificate authority, installed as trusted on every client. This image deliberately does not ship that: its start-up check refuses to run E2guardian with anything in /etc/e2guardian/private or with enablessl = on. If you build that yourself, generate the authority on your own instance, never copy one between instances, and adjust the start-up check knowingly.

Step 10: Metadata access is blocked

Neither service can reach the instance metadata service, and a client that asks the proxy for it is refused by Squid (403, ERR_ACCESS_DENIED):

systemctl show -p IPAddressDeny e2guardian.service squid.service | grep .
curl -s -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:8080 http://169.254.169.254/latest/meta-data/
curl -s -D - -o /dev/null -x http://127.0.0.1:8080 http://169.254.169.254/latest/meta-data/ | grep -i '^X-Squid-Error'
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
403
X-Squid-Error: ERR_ACCESS_DENIED 0

Squid's access rules refuse the metadata addresses first, then link-local and loopback destinations, ports outside the safe list, CONNECT to anything but 443 and the cache manager, and allow only the instance itself:

grep -E '^(http_access|http_port)' /etc/squid/squid.conf
http_access deny to_metadata
http_access deny to_linklocal
http_access deny to_localhost
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny manager
http_access allow localhost
http_access deny all
http_port 127.0.0.1:3128

Step 11: How the fail-closed start works

e2guardian.service runs only when first boot's ready marker exists, only together with the allow-list unit and Squid, and every start runs a check as root first:

systemctl cat e2guardian.service | grep -E '^(ConditionPathExists|Requires|ExecStartPre|ExecStart)='
sudo stat -c '%a %U:%G %n' /root/squid-e2guardian-info.txt /etc/e2guardian/allowed-clients.txt /etc/e2guardian/private
Requires=e2guardian-firewall.service squid.service
ConditionPathExists=/var/lib/cloudimg/squid-e2guardian-ready
ExecStartPre=+/usr/local/sbin/squid-e2guardian-preflight
ExecStart=/usr/local/sbin/e2guardian -N -c /etc/e2guardian/e2guardian.conf
600 root:root /root/squid-e2guardian-info.txt
644 root:root /etc/e2guardian/allowed-clients.txt
700 root:root /etc/e2guardian/private

Step 12: Logs and rotation

E2guardian logs every request (time, client address, URL, action, filter group) to /var/log/e2guardian/access.log, which is rotated daily and kept for 14 days. Squid's access log is rotated by the Ubuntu package and does not record query strings (strip_query_terms on). Treat both logs as sensitive: they show which client visited which site.

cat /etc/logrotate.d/e2guardian
/var/log/e2guardian/*.log {
    su e2guardian e2guardian
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    create 0640 e2guardian e2guardian
}

Step 13: Security recommendations

  • Keep SSH open only to your management addresses. Open tcp/8080 only to the networks the proxy serves, never to 0.0.0.0/0.
  • Keep /etc/e2guardian/allowed-clients.txt to the ranges that really need the proxy.
  • Leave TLS interception off unless you run your own certificate authority and manage client trust deliberately.
  • Do not enable the header authentication plugin before E2guardian 5.5.10 (see the security notes).
  • Leave unattended security upgrades on: Squid and the operating system update from Ubuntu. E2guardian is compiled into /usr/local; cloudimg ships updated versions as new versions of this listing.

Support and licensing

E2guardian is open-source software by Frederic Bourgeois, Philip Pearce and contributors, distributed under the GNU General Public License version 2 with an exception permitting linking with OpenSSL. As required by the GPL, the complete source code of the E2guardian binaries on this image, the exact build options and a written offer valid for three years are in /usr/share/doc/cloudimg/. Squid is distributed by the Squid project under the GNU General Public License version 2 or later; it is the unmodified Ubuntu package, whose source is available from the Ubuntu archive. cloudimg provides the packaging, the secure defaults, the VPC allow-list, the Squid metadata and loopback refusals, the metadata block, the fail-closed start, the self-test and helpers, and 24/7 support.

cloudimg is not affiliated with or endorsed by the E2guardian project, the Squid project or the Squid Software Foundation. E2guardian and Squid are used here only to identify the software.

For help with deployment or configuration, email support@cloudimg.co.uk or visit cloudimg support.