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 sudo privileges and UFW enabled with SSH allowed.
  • The public IP address of the machine you will connect from, referred to as your_client_ip.

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:

  • acl lines define named conditions (a user is authenticated, a port is 443, a domain is in a list). They do nothing on their own.
  • http_access lines use those conditions to allow or deny requests. Order matters: unsafe ports and blocked domains are denied before authenticated users are allowed, and deny all catches everything else.
  • CONNECT is 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 256 creates 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"

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 parse and journalctl -u squid -n 50. A missing /etc/squid/blocked_domains.txt or passwords file is a common cause.
  • curl: (7) Failed to connect. The firewall is blocking the client. Check that your_client_ip is your real public IP (curl -4 https://ifconfig.me on the client) and that it appears in sudo ufw status.
  • 407 even with the right password. Test the helper as in Step 2. If it prints ERR, recreate the user with htpasswd; if it cannot open the file, fix the owner and permissions.
  • 403 for sites that should work. A rule above http_access allow authenticated matched. Check the blocklist; .example.com matches every subdomain of example.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.