Squid is a mature open-source forward proxy: clients send their web requests to it, and Squid fetches the content on their behalf, optionally caching it, filtering it and logging every request. In this tutorial you will install Squid on Ubuntu 24.04, lock it down so only authenticated users can use it, block a list of domains, and test it from a client with curl and a browser.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 1 GB of RAM and a few GB of free disk space for the cache.
- A non-root user with
sudoprivileges and UFW enabled with SSH allowed. - The public IP address of the machine you will connect from, referred to as
your_client_ip.
WarningA proxy that accepts connections from anyone (an "open proxy") is found by scanners within hours and abused for spam and attacks, which gets your IP blocklisted. Every configuration in this guide requires authentication and ends with
http_access deny all.
Step 1 - Installing Squid
Squid is in the Ubuntu repositories. Install it together with apache2-utils, which provides the htpasswd tool you will use to create proxy users:
sudo apt update
sudo apt install squid apache2-utils
The service starts automatically. Check its status:
systemctl status squid --no-pager
The output should show active (running). Ubuntu 24.04 ships Squid 6, which you can confirm with squid -v | head -n 1.
Step 2 - Creating proxy users
Squid can check usernames and passwords against a file in htpasswd format with its basic_ncsa_auth helper. Create the file and the first user, replacing your_user with the username you want:
sudo htpasswd -c /etc/squid/passwords your_user
You will be asked for the password twice. To add more users later, run the same command without -c, which would otherwise overwrite the file.
Squid runs as the proxy user, so it needs read access to the file, while other users should not:
sudo chown root:proxy /etc/squid/passwords
sudo chmod 640 /etc/squid/passwords
Test the helper directly by typing the username and password separated by a space:
echo 'your_user your_password' | sudo -u proxy /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
OK
A wrong password prints ERR.
Step 3 - Writing a minimal configuration
The default /etc/squid/squid.conf is over 9,000 lines, almost all comments, and by default only allows clients on private networks. Keep it as a reference and write a short configuration you fully understand:
sudo mv /etc/squid/squid.conf /etc/squid/squid.conf.orig
sudo nano /etc/squid/squid.conf
Paste the following:
# Port Squid listens on
http_port 3128
# Authentication with the htpasswd file
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic realm Squid proxy
auth_param basic credentialsttl 2 hours
acl authenticated proxy_auth REQUIRED
# Ports clients may connect to
acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
acl Safe_ports port 1025-65535
acl CONNECT method CONNECT
# Domains nobody may visit
acl blocked_sites dstdomain "/etc/squid/blocked_domains.txt"
# Access rules, evaluated top to bottom; the first match wins
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access deny blocked_sites
http_access allow authenticated
http_access deny all
# Cache: 256 MB in memory, 2 GB on disk
cache_mem 256 MB
maximum_object_size 100 MB
cache_dir ufs /var/spool/squid 2000 16 256
coredump_dir /var/spool/squid
# Don't reveal client IPs to the websites they visit
forwarded_for delete
via off
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
The key parts are:
acllines define named conditions (a user is authenticated, a port is 443, a domain is in a list). They do nothing on their own.http_accesslines use those conditions to allow or deny requests. Order matters: unsafe ports and blocked domains are denied before authenticated users are allowed, anddeny allcatches everything else.CONNECTis the method browsers use to tunnel HTTPS through the proxy. Squid cannot see or cache the content of HTTPS sites, but it still logs the domain and applies the rules above.cache_dir ufs /var/spool/squid 2000 16 256creates a 2,000 MB disk cache split into 16 first-level and 256 second-level directories.
Create the blocklist file, one domain per line. A leading dot also matches all subdomains:
sudo nano /etc/squid/blocked_domains.txt
.facebook.com
.tiktok.com
Check the configuration for errors:
sudo squid -k parse
The command prints the configuration it processed; look for lines containing ERROR or FATAL. If there are none, the file is valid.
Step 4 - Initializing the cache and restarting Squid
The disk cache directories must exist before Squid can use them. Stop the service, create them, and start it again:
sudo systemctl stop squid
sudo squid -z --foreground
sudo systemctl start squid
Confirm Squid is listening on port 3128:
sudo ss -tlnp | grep 3128
LISTEN 0 256 *:3128 *:* users:(("squid",pid=5120,fd=13))
Step 5 - Opening the firewall
Even with authentication, there is no reason to expose the proxy to the whole internet. Allow port 3128 only from the addresses that will use it:
sudo ufw allow from your_client_ip to any port 3128 proto tcp
Repeat the command for each additional client address, then check the rules with sudo ufw status.
Step 6 - Testing the proxy
From your client machine, request a page through the proxy with curl. The -x option sets the proxy and -U the credentials:
curl -x http://your_server_ip:3128 -U your_user:your_password -I https://example.com
HTTP/1.1 200 Connection established
HTTP/2 200
content-type: text/html
...
The first 200 Connection established comes from Squid, the second from the website. Now check that the rules work.
Without credentials, Squid refuses the request:
curl -x http://your_server_ip:3128 -I https://example.com
HTTP/1.1 407 Proxy Authentication Required
A blocked domain is rejected even with valid credentials:
curl -x http://your_server_ip:3128 -U your_user:your_password -I https://www.facebook.com
HTTP/1.1 403 Forbidden
Finally, confirm that the requests are logged on the server:
sudo tail -n 3 /var/log/squid/access.log
1759312000.123 412 198.51.100.23 TCP_TUNNEL/200 5120 CONNECT example.com:443 your_user HIER_DIRECT/93.184.215.14 -
1759312005.456 0 198.51.100.23 TCP_DENIED/407 3920 CONNECT example.com:443 - HIER_NONE/- text/html
1759312010.789 0 198.51.100.23 TCP_DENIED/403 3874 CONNECT www.facebook.com:443 - HIER_NONE/- text/html
Each line shows the client IP, the result code, the destination and the authenticated user.
Step 7 - Configuring clients
To use the proxy from a browser or the whole operating system, set a manual HTTP and HTTPS proxy of your_server_ip on port 3128:
- Firefox: Settings > Network Settings > Manual proxy configuration, and check "Also use this proxy for HTTPS".
- Windows: Settings > Network & internet > Proxy > Manual proxy setup.
- macOS: System Settings > Network > your connection > Details > Proxies, enable "Web proxy (HTTP)" and "Secure web proxy (HTTPS)".
The browser asks for the username and password on first use. For command-line tools on Linux, export the standard variables:
export http_proxy="http://your_user:your_password@your_server_ip:3128"
export https_proxy="$http_proxy"
ImportantThe connection between the client and Squid is plain HTTP, and basic authentication only encodes the password, it does not encrypt it. Use the proxy from trusted networks, or reach it through a VPN such as WireGuard and allow port 3128 only on the VPN interface.
Managing Squid day to day
After editing squid.conf or the blocklist, validate and apply the changes without dropping active connections:
sudo squid -k parse
sudo systemctl reload squid
Squid's logs are rotated daily by logrotate (/etc/logrotate.d/squid). To see how much of the traffic is served from the cache, count the result codes in the access log:
sudo awk '{print $4}' /var/log/squid/access.log | cut -d/ -f1 | sort | uniq -c | sort -rn
1834 TCP_TUNNEL
212 TCP_MISS
97 TCP_HIT
41 TCP_DENIED
TCP_HIT and TCP_MEM_HIT are requests served from the cache. Since most traffic today is HTTPS (TCP_TUNNEL), expect a low hit rate unless clients download a lot of plain HTTP content such as package repositories.
Troubleshooting
- Squid fails to start. Run
sudo squid -k parseandjournalctl -u squid -n 50. A missing/etc/squid/blocked_domains.txtor passwords file is a common cause. curl: (7) Failed to connect. The firewall is blocking the client. Check thatyour_client_ipis your real public IP (curl -4 https://ifconfig.meon the client) and that it appears insudo ufw status.407even with the right password. Test the helper as in Step 2. If it printsERR, recreate the user withhtpasswd; if it cannot open the file, fix the owner and permissions.403for sites that should work. A rule abovehttp_access allow authenticatedmatched. Check the blocklist;.example.commatches every subdomain ofexample.com.
Conclusion
You now have a Squid forward proxy on Ubuntu 24.04 that only serves authenticated users from known addresses, blocks unwanted domains, caches cacheable content and logs every request. From here you can define time-based ACLs with acl work_hours time, limit bandwidth per user with delay pools, or chain this proxy to an upstream one with cache_peer.
