Proxy Server with FreeBSD and Squid (Part 2)


Previously, I discussed how to configure a Squid proxy.  The proxy is opaque that the web browsers have to be configured.  I continue to explain how a proxy can be made transparent; when web browsers go to the Internet, the requests gets intercepted and be processed by the proxy.  Like before, I use PF firewall and let it redirect the packets for me.

Step 1: Configure Network Gateway

In order to configure a a network router, it needs to have two network interfaces, virtual or physical.  One of them connects to the external world (through another router, maybe).  Another one connects to the intranet.  In PF, it is recommended to set up macros to determine the external and internal interfaces.  An example rule set will be as follows, where a Realtek was used as external and a Broadcom as internal.

nat pass on $extif from $intif:network to any -> ($extif)
pass in quick from $intif:network to any
pass out quick

In order for a FreeBSD server act as a router, it has to have the gateway variable enabled in /etc/rc.conf:


Once these are configured, reload the firewall rules for a smoke test.  Good luck.

Step 2: Configure Network Clients

Pick a computer and configure its network traffic through the router.  Technically, we change the gateway.

Microsoft Windows: Control Panel > Network and Sharing Centre > Network Interfaces > Properties > TCP/IP Version 4 > Configure > Gateway

Mac OS X: System Preference > Network > Gateway

FreeBSD: Update variable “defaultrouter” in /etc/rc.conf, then reboot

Everything should behave similar, except the network goes through the router.  Hopefully, the network link LEDs could give you some hints.  (Sorry being lazy not telling the proper way…)

Step 3: Packet Redirection and Squid

In PF configuration, add this line right after the NAT rule, and then reload:

rdr pass on $intif proto tcp from any to any port 80 -> ($intif) port 3129

In Squid configuration, add this line right after the original http port statement:

http_port 3129 intercept

I may explain what ‘intercept’ mode means in the next article…

Step 4: Testing

Use the client configured in the step 2 to browse the web.  Like last time, there should be some pages cached.  But make sure you visit pages that are not encrypted (like https); otherwise the proxy will not take effect.

Step 5: To be Continued

In the part 3 of this series, I will explain how to to intercept HTTPS connections as well.


Proxy Server with FreeBSD and Squid (Part 1)


When one has multiple machines within a cloud network, it is natural to ask for centralised network traffic, data files, credential service, etc.  In this article, I focus on centralising network traffic, in particular, the world wide web.

With the world wide web traffic centralised, the proxy server can accelerate the download processes of some frequently accessed files, such as operating system patches.

In this part, we install Squid as an opaque proxy server, and configure some clients to use it.  We will handle the transparent proxy in the next part.

Step 1: Install Squid

Installing Squid is easy as usual.  But to make it even smoother, install the SSL root certificates.

# pkg install squid ca_root_nss

The squid requires Perl which, since FreeBSD 5.0, no longer installed by default.  The package installer will handle it.

Step 2: Smoke Test

Even though there are quite a page of notice upon installing Squid, the default Squid installation is good enough to fire without configuration:

# sysrc squid_enable=YES
# service squid start

or, for the old style…

# echo squid_enable=YES >> /etc/rc.conf
# /usr/local/etc/rc.d/squid start

Step 3: Configure Squid

The Squid refers to its configuration file in “/usr/local/etc/squid”.

# ee /usr/local/etc/squid/squid.conf


What shall we configure?  Here are some suggestions:

  1. Configure the intranet address ranges.  By the configuration file, only networks defined as “localnet” is granted access.  For example, I only use the class A private subnet, so I disable all others.
    acl localnet src     
    #acl localnet src 
    #acl localnet src
    #acl localnet src fc00::/7      
    #acl localnet src fe80::/10
  2. Deny the squid accessing the so-called “localhost”.  Internal network of the squid is not supposed to be accessed by others.
    http_access deny to_localhost
  3. Configure the cache directory.  For example, here I configure a 10000 MB cache space.  There are two levels of directories, with 16 and 256 directories per level respectively.
    cache_dir ufs /var/squid/cache 10000 16 256
  4. Prefer IPv4 whenever possible.  This is great if your network is not IPv6 ready.
    dns_v4_first on

We then stop the Squid, create the cache directory, and restart.

# service squid stop
# squid -z -N
# chown -R squid:squid /var/squid/cache
# service squid start

Step 4: Update Firewall

If you are using PF firewall, you will need to update the rules to allow the port.  For example, I only use the “vtnet1” as intranet, and it is accepting port 3128 (the default squid service port).  You may refer to the configuration of the VPN notes as example.

# cat >> /etc/pf.conf << EOF
pass in quick on $intif inet proto tcp from any to any port $inttcpports keep state
# service pf reload

Step 5: Playing with Telnet

The title is not a typo.  We now test the system with the most geeky way—enter the HTTP request manually.  FreeBSD comes with a telnet client and it is handy for various testing.  Suppose the address is and we connect to the port 3128 of it.  After typing the GET statement, remember to hit the enter key twice to complete the request.

# telnet 3128

HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Tue, 07 Mar 2017 16:04:30 GMT
Content-Type: text/html
Content-Length: 178
X-Cache: MISS from singapura-roteador
X-Cache-Lookup: HIT from singapura-roteador:3128
Via: 1.1 singapura-roteador (squid/3.5.23)
Connection: close

<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
Connection closed by foreign host.

The HTTP return code 301 indicates another URL for access.  What about following it?

# telnet 3128

Step 6: Troubleshoot

Here are some errors you may encounter:

Unable to connect to the server: try disabling the “pf” service briefly and retry.  If it works, you will need to update your firewall rules.

Squid is not starting after enabling cache: make sure you create the cache directory and set the proper ownership with the chown command (as above) .

Getting 503 error with ERR_CONNECT_FAIL: review the error message and if the address is an IPv6 address, there could be issues with the IPv6 routing and you can consider using the “dns_v4_first” option (as above).

Getting 503 error with ERR_SECURE_CONNECT_FAIL: review the website with your own browser, ensure you have installed the common root certificates “ca_root_nss” package (as above).

Step 7: Configure Client

Since our proxy is not transparent yet, the clients have to be manually configured in order to use the proxy.  Depending on the hosts you have on the same intranet, here are the configuration methods for your reference:

Mac OS X: System Preferences > Network > Advanced > Proxies > Web Proxy / Secure Web Proxy

Internet Explorer on Windows: Tools > Internet Options > Connections > LAN Setting

Firefox on Windows: Tools > Internet Options > Network > Connections > Settings

FreeBSD shell: export “HTTP_PROXY” variable in “.cshrc”, like “setenv HTTP_PROXY;

Step 8: Is the Proxy Really Running?

There are some barbaric ways to check if the proxy is running:

Check the number of files the cache: “find /var/squid/cache | wc -l”

Check the Squid access log: “less /var/log/squid/access.log”

Step 9: To be Continued

A few weeks later, we will revisit Squid and configure the network routers to transparently direct world wide web requests to the proxy server, etc.

Later this week, we may come up with an article not related with FreeBSD.  The next FreeBSD-related article, hopefully next week, will be likely related to programming.  Stay tuned.