Squid Basics
What Squid is
Squid is a caching and forwarding proxy server.
What a proxy is
A proxy sits between a client and the destination server. Instead of:
client → website
You get:
client → proxy → website
Common reasons to use a (forward) proxy:
- Control and log outbound access
- Apply ACL rules to what clients can reach
- Caching to reduce bandwidth
- Network separation (clients in an isolated network)
What a reverse proxy is
A reverse proxy is different — it represents the server to incoming clients, not the client to the outside world:
user → reverse proxy → backend app
Common reasons to use a reverse proxy (Nginx, Apache, HAProxy):
- TLS termination — handle HTTPS at the proxy, plain HTTP internally
- Load balancing across multiple backends
- Hiding internal service details
- Routing requests to multiple internal apps under one hostname
- Central logging and access control
Main config
/etc/squid/squid.conf
ACL example
acl localnet src 192.168.1.0/24
http_access allow localnet
http_access deny all
http_port 3128
What this means:
- Define an ACL called
localnetmatching that subnet - Allow requests from that ACL
- Deny everyone else
- Listen on port 3128
deny all.
Log files
/var/log/squid/access.log # client requests
/var/log/squid/cache.log # operational problems
Service checks
systemctl status squid
systemctl restart squid
journalctl -u squid -n 50
Troubleshooting
- Service running
- Port 3128 listening:
ss -tulpn | grep squid - ACL order — check if a deny rule is above the allow rule you expect to match
- Client configured to use the proxy (
http_proxyenv var or browser settings) - Access log showing allowed or denied traffic
Config validation and live reload
The squid -k command sends signals to the running squid process. The most important are parse (validate config) and reconfigure (live reload).
# Validate the config file without restarting
squid -k parse
# If valid: no output (exit 0)
# If invalid: specific error with line number:
# FATAL: /etc/squid/squid.conf line 42: invalid ACL type 'destdomain'
# Reload config without dropping connections (graceful)
squid -k reconfigure
# Rotate log files (useful for log management scripts)
squid -k rotate
# Shutdown gracefully
squid -k shutdown
Always run squid -k parse before squid -k reconfigure or systemctl restart squid. A bad config kills the proxy for all clients without warning.
- Edit
/etc/squid/squid.conf squid -k parse— validatesquid -k reconfigure— apply without dropping connectionstail -f /var/log/squid/access.log— verify traffic is flowing
visible_hostname directive
Without visible_hostname, Squid generates a startup warning and may use an incorrect or ugly hostname in error pages and Via headers. Set it explicitly to suppress the warning and control how the proxy identifies itself.
# /etc/squid/squid.conf
visible_hostname proxy01.internal.example.com
The warning you see without this directive: WARNING: Could not determine this machine's hostname. Please set 'visible_hostname'. This appears in /var/log/squid/cache.log on every startup.
# Full minimal squid.conf with visible_hostname
visible_hostname proxy01.internal.example.com
http_port 3128
# Internal network allowed
acl localnet src 10.0.0.0/8
acl localnet src 172.16.0.0/12
acl localnet src 192.168.0.0/16
http_access allow localnet
http_access deny all
CONNECT and ssl_bump
For HTTPS, clients ask Squid to open an opaque tunnel using the CONNECT method — everything after the TLS handshake is end-to-end encrypted and Squid only sees the destination host and byte counts. Two side effects to remember:
- The
access.logline showsCONNECT example.com:443, not a URL path. - URL/content filters that work for plain HTTP do not see HTTPS URLs unless you terminate the TLS — see Squid SSL-Bump for peeking at SNI (peek-and-splice) or full man-in-the-middle inspection with a locally-issued CA.
WPAD / PAC
WPAD (Web Proxy Auto-Discovery) lets browsers find the proxy automatically by fetching a PAC (Proxy Auto-Config) file from a well-known URL — http://wpad.<domain>/wpad.dat. You publish the file on an internal web server (and/or resolve wpad in DNS) and clients pick it up with zero manual config.
// /var/www/html/wpad.dat (MIME type application/x-ns-proxy-autoconfig)
function FindProxyForURL(url, host) {
// Direct for RFC1918 and internal zones — no proxy needed
if (isPlainHostName(host) ||
dnsDomainIs(host, ".internal.example.com") ||
isInNet(host, "10.0.0.0", "255.0.0.0") ||
isInNet(host, "172.16.0.0", "255.240.0.0") ||
isInNet(host, "192.168.0.0","255.255.0.0")) {
return "DIRECT";
}
// Everything else goes through the proxy with a fallback
return "PROXY proxy01.internal.example.com:3128; " +
"PROXY proxy02.internal.example.com:3128; " +
"DIRECT";
}
Serve the file as application/x-ns-proxy-autoconfig and make both wpad.<domain> and wpad resolve in DNS (browsers walk the DNS suffix list). Test with curl -H 'Accept: */*' http://wpad.internal.example.com/wpad.dat — a 404 or wrong MIME type will make clients silently fall back to DIRECT.
Authentication helpers
Squid does not do authentication itself — it calls an external helper and acts on the result. The helper is picked in squid.conf via auth_param.
Basic auth with a flat file (basic_ncsa_auth)
# /etc/squid/squid.conf
auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/htpasswd
auth_param basic realm SysRef Proxy
auth_param basic children 5
acl authenticated proxy_auth REQUIRED
http_access allow authenticated
http_access deny all
# Create the password file (htpasswd from httpd-tools)
htpasswd -c /etc/squid/htpasswd alice
chmod 640 /etc/squid/htpasswd
chown root:squid /etc/squid/htpasswd
squid -k reconfigure
Kerberos / SPNEGO (negotiate_kerberos_auth)
# /etc/squid/squid.conf — single-sign-on against FreeIPA/AD
auth_param negotiate program /usr/lib64/squid/negotiate_kerberos_auth \
-s HTTP/proxy01.internal.example.com@EXAMPLE.COM
auth_param negotiate children 10
auth_param negotiate keep_alive on
acl kerb_users proxy_auth REQUIRED
http_access allow kerb_users
http_access deny all
# Required environment bits:
# - A keytab at /etc/squid/HTTP.keytab owned by squid, mode 0640
# - KRB5_KTNAME=/etc/squid/HTTP.keytab exported to the squid service
# (drop-in: /etc/systemd/system/squid.service.d/krb.conf)
systemctl edit squid
# [Service]
# Environment=KRB5_KTNAME=/etc/squid/HTTP.keytab
# Sanity check — does the helper work on the CLI?
echo 'YR' | /usr/lib64/squid/negotiate_kerberos_auth -d
Basic auth is simple but credentials cross the wire on every request — acceptable only inside a TLS-bumped setup or over a trusted LAN. Kerberos is the right choice in any FreeIPA/AD environment: users get transparent SSO and the proxy never sees a password. See Kerberos and Keytab Rotation for the identity side.