Skip to content

Squid: Internet Forwarding to Remote VM

Your VM in the cloud has no public IP or internet access is blocked via NAT, but the deployment needs wget/curl from inside. Squid on an intermediate host with a decent uplink solves this in ten minutes.

Why This Is Needed

I forward internet through Squid when a VM sits in an isolated network segment. An intermediate host with a public IP and network access becomes the proxy server. The application on the remote machine routes traffic through the tunnel.

Real-world cases: test environments without external connectivity, CI/CD agents in a private subnet, temporary traffic routing for debugging.

Installing and Basic Squid Setup

Install on the intermediate host (Ubuntu/Debian):

apt update && apt install -y squid

The default config lives in /etc/squid/squid.conf. Minimum working config:

# /etc/squid/squid.conf
http_port 3128

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

Enable and start:

systemctl enable --now squid

Verify the port is listening:

ss -tlnp | grep 3128

ACL and Port Configuration

If access should be only via SSH tunnel from a specific address, replace localnet with the exact IP:

# Proxy accessible only from this address
acl tunneled src 203.0.113.50

http_access allow tunneled
http_access deny all

To change the port:

http_port 8080

After config changes, reload without restarting:

squid -k reconfigure
Note

If Squid fails to start after changes, check the log: journalctl -u squid -n 50.

SSH Tunnel to VM

On the remote machine, establish a tunnel to the intermediate host:

ssh -N -L 3128:localhost:3128 user@proxy-host

-N — don’t open a shell, forwarding only. -L binds local port 3128 to localhost:3128 on the remote host.

For background:

ssh -N -L 3128:localhost:3128 user@proxy-host &

Or via a systemd user service:

# ~/.config/systemd/user/proxy-tunnel.service
[Unit]
Description=SSH tunnel to proxy-host

[Service]
ExecStart=/usr/bin/ssh -N -L 3128:localhost:3128 user@proxy-host
Restart=always
RestartSec=10

[Install]
WantedBy=default.target
systemctl --user enable --now proxy-tunnel.service

Client Proxy Setup

On the remote VM, set environment variables for applications that respect http_proxy:

export http_proxy=http://localhost:3128
export https_proxy=http://localhost:3128

Or permanently in /etc/environment:

http_proxy=http://localhost:3128
https_proxy=http://localhost:3128

For curl/wget, variables suffice. For apt — additionally:

echo 'Acquire::http::Proxy "http://localhost:3128";' | tee /etc/apt/apt.conf.d/99proxy

Test:

curl -s --max-time 10 https://ifconfig.me

If it returns the intermediate host IP — it’s working.

Verification and Logging

Squid access log:

tail -f /var/log/squid/access.log

Format: time client/status code size method URL

Sample entry:

1703123456.123  1024 192.168.1.100 TCP_MEM_HIT/200 5123 GET http://example.com/file.tar.gz

Response codes: TCP_HIT — served from cache, TCP_MISS — fetched from network, TCP_DENIED — access denied by ACL.

To clear the cache before testing:

squid -k shutdown && rm -rf /var/spool/squid/* && squid -z && systemctl start squid
FlagDescription
http_portListening port
acl name src IP/maskAccess rule by IP
http_access allow|denyPermit or deny ACL
-k reconfigureReload config
-k shutdownGraceful stop
-zInitialize cache directories
Warning

Squid caches responses by default. For debugging, disable caching: add cache deny all to the config, then run squid -k reconfigure.

Nine minutes of setup — and the isolated VM has internet via proxy. If you need HTTPS transparent mode with certificate substitution — that’s a different story involving SSL-bump and CA generation.