My double proxy solution to LaLiga blocks


If you are not aware, LaLiga (Spain’s football league) is blocking thousands of IPs in Spain every time there’s a football match on the TV to try to fight against the pirated football on the Internet. Of course it’s not working as the pirate sites continue being accessible without a hinch, but thousands of legitimate webs stop working. You can get more information about the affected IPs in the fantastic page ¿Hay ahora fútbol?.

I recently discovered that some strange errors I was seeing in some of my home lab services were caused by these blocked IPs. The affected IPs are hickjacked and the HTTP connections redirected to LaLiga’s web server. HTTPS connections will fail with a certificate error like this:

[Error] X509CertificateValidationService: Certificate validation for api.radarr.video failed. RemoteCertificateNameMismatch, RemoteCertificateChainErrors

To avoid these problems I have created this solution with two proxies and a VPN.

I initially just used one proxy connected to the VPN using the gluetun container. The solution worked, but now I was having issues with some RSS feeds that rejected connections from VPN IPs (sigh… ☹️). My solution? add another proxy! this time without VPN. The first proxy is configured with a list of domains that have problems being accessed from the VPN and requests those domains to the second proxy. See the configuration below.

Quadlet units:

# cat /etc/containers/systemd/squid.network
[Network]
NetworkName=squid
IPv6=true

# cat /etc/containers/systemd/gluetun-squid.volume
[Volume]
VolumeName=gluetun-squid

# cat /etc/containers/systemd/gluetun-squid.container
[Container]
AddCapability=NET_ADMIN NET_BIND_SERVICE NET_RAW
AddDevice=/dev/net/tun
ContainerName=gluetun-squid
EnvironmentFile=/etc/gluetun/gluetun-squid-env
Image=ghcr.io/qdm12/gluetun:v3.41.1
Network=squid.network
NoNewPrivileges=true
PublishPort=3129:3129
UserNS=auto
Volume=gluetun-squid.volume:/gluetun:U,Z
PodmanArgs=--cpu-shares 256
PodmanArgs=--memory 512m
AutoUpdate=registry

[Install]
WantedBy=multi-user.target default.target

[Service]
Restart=always
RestartSec=5

[Unit]
Description=Gluetun VPN


# cat /etc/containers/systemd/squid-vpn.container
[Container]
ContainerName=squid-vpn
DropCapability=ALL
Image=quay.io/jorti/squid:latest
Network=container:gluetun-squid
NoNewPrivileges=true
ReadOnly=true
UserNS=auto
Volume=/etc/squid/vpn/squid.conf:/etc/squid/squid.conf:ro,Z
PodmanArgs=--cpu-shares 512
PodmanArgs=--memory 1g
AutoUpdate=registry

[Install]
WantedBy=multi-user.target default.target

[Service]
Restart=always
RestartSec=5

[Unit]
Description=Squid web proxy with VPN
After=gluetun-squid.service
BindsTo=gluetun-squid.service

# cat /etc/containers/systemd/squid.container
[Container]
ContainerName=squid
DropCapability=ALL
Image=quay.io/jorti/squid:latest
Network=squid.network
NoNewPrivileges=true
ReadOnly=true
UserNS=auto
Volume=/etc/squid/direct/squid.conf:/etc/squid/squid.conf:ro,Z
PodmanArgs=--cpu-shares 512
PodmanArgs=--memory 1g
AutoUpdate=registry

[Install]
WantedBy=multi-user.target default.target

[Service]
Restart=always

[Unit]
Description=Squid web proxy

First proxy configuration (VPN), with the list of domains to be excluded from the VPN:

/etc/squid/vpn/squid.conf:

acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8  # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10  # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16  # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12  # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16  # RFC 1918 local private network (LAN)
acl localnet src fc00::/7        # RFC 4193 local private network range
acl localnet src fe80::/10       # RFC 4291 link-local (directly plugged) machines
acl to_localnet dst 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl to_localnet dst 10.0.0.0/8  # RFC 1918 local private network (LAN)
acl to_localnet dst 100.64.0.0/10  # RFC 6598 shared address space (CGN)
acl to_localnet dst 169.254.0.0/16  # RFC 3927 link-local (directly plugged) machines
acl to_localnet dst 172.16.0.0/12  # RFC 1918 local private network (LAN)
acl to_localnet dst 192.168.0.0/16  # RFC 1918 local private network (LAN)
acl to_localnet dst fc00::/7        # RFC 4193 local private network range
acl to_localnet dst fe80::/10       # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl SSL_ports port 6443 # OpenShift
acl SSL_ports port 2053 # Discord
acl SSL_ports port 5222 # web.whatsapp.com
acl SSL_ports port 5228 # mtalk.google.com
acl Safe_ports port 80  # http
acl Safe_ports port 21  # ftp
acl Safe_ports port 443  # https
acl Safe_ports port 70  # gopher
acl Safe_ports port 210  # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280  # http-mgmt
acl Safe_ports port 488  # gss-http
acl Safe_ports port 591  # filemaker
acl Safe_ports port 777  # multiling http
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localhost
http_access deny to_localhost
http_access deny to_linklocal
http_access deny to_localnet
http_access allow localnet
http_access deny all
http_port 3129
coredump_dir /var/spool/squid
refresh_pattern ^ftp:  1440 20% 10080
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern .  0 20% 4320
shutdown_lifetime 2 seconds
pid_filename none
cache_log stdio:/dev/stderr
access_log stdio:/dev/stdout

# Direct proxy
cache_peer squid.dns.podman parent 3128 0 no-query no-digest default

# Domains to send through the direct proxy
acl no_vpn_domains dstdomain .example1.com
acl no_vpn_domains dstdomain .example2.com
cache_peer_access squid.dns.podman allow no_vpn_domains
cache_peer_access squid.dns.podman deny all
never_direct allow no_vpn_domains

Second proxy configuration (direct):

/etc/squid/direct/squid.conf:

acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8  # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10  # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16  # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12  # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16  # RFC 1918 local private network (LAN)
acl localnet src fc00::/7        # RFC 4193 local private network range
acl localnet src fe80::/10       # RFC 4291 link-local (directly plugged) machines
acl to_localnet dst 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl to_localnet dst 10.0.0.0/8  # RFC 1918 local private network (LAN)
acl to_localnet dst 100.64.0.0/10  # RFC 6598 shared address space (CGN)
acl to_localnet dst 169.254.0.0/16  # RFC 3927 link-local (directly plugged) machines
acl to_localnet dst 172.16.0.0/12  # RFC 1918 local private network (LAN)
acl to_localnet dst 192.168.0.0/16  # RFC 1918 local private network (LAN)
acl to_localnet dst fc00::/7        # RFC 4193 local private network range
acl to_localnet dst fe80::/10       # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl SSL_ports port 6443 # OpenShift
acl SSL_ports port 2053 # Discord
acl SSL_ports port 5222 # web.whatsapp.com
acl SSL_ports port 5228 # mtalk.google.com
acl Safe_ports port 80  # http
acl Safe_ports port 21  # ftp
acl Safe_ports port 443  # https
acl Safe_ports port 70  # gopher
acl Safe_ports port 210  # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280  # http-mgmt
acl Safe_ports port 488  # gss-http
acl Safe_ports port 591  # filemaker
acl Safe_ports port 777  # multiling http
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localhost
http_access deny to_localhost
http_access deny to_linklocal
http_access deny to_localnet
http_access allow localnet
http_access deny all
http_port 3128
coredump_dir /var/spool/squid
refresh_pattern ^ftp:  1440 20% 10080
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern .  0 20% 4320
shutdown_lifetime 2 seconds
pid_filename none
cache_log stdio:/dev/stderr
access_log stdio:/dev/stdout

See also