Setting network proxy on linux desktop
Tags: linux, proxy, beginners
Published: 2021-12-20 18:44:15

I was trying to write a script to setup system wide proxy on my Ubuntu desktop. Turns out, Linux makes it way too difficult to configure a proxy across *all* apps. 

# Table of Contents
  * [App Specific Proxies](#app-specific)
  * [Gnome network settings](#gnome-network-setting)
  * [Using Environment Variables](#terminal-proxy)
  * [Configure Firewall](#iptables)

<br/>
## 0. Setting app specific proxies <a name="app-specific"></a>

Most web browsers (*Firefox in particular*) have their own internal proxy settings. There is abundant documentation for all of these on their respective websites.

## 1. Gnome network settings <a name="gnome-network-setting"></a>

If you are using Gnome, you can go to `Settings > Network > Network Proxy`. Select `Manual` and enter the proxy details.

This the most obvious method and it covers most general use cases like using a proxy for WiFi inside a corporate or university network.

![Gnome Network settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/447xnzvwb8uyni3zxtca.png)

Under the hood, this sets attributes in `gconf`(*maybe `dconf` in modern distros*). This can be done from the terminal as:

```shell
gsettings set org.gnome.system.proxy mode 'manual'
gsettings set org.gnome.system.proxy.http enabled true
gsettings set org.gnome.system.proxy.http host 'proxy.server.addr'
gsettings set org.gnome.system.proxy.http port proxy_port
```

## 2. Setting environment variables <a name="terminal-proxy"></a>

The previous method does not always work for shell instances. A proven way for using a proxy while working on the terminal (either while doing a simple curl, or while launching an app) is by setting environment variables like `http_proxy` or `HTTP_PROXY` to set a proxy for all http request. 

> **Note:** you might want to set both the uppercase and the lowercase version. This is necessary because, without a proper standard, over the years apps and languages either support both (with a set of priorities) or any one of the two. This leads to some long, head scratching debugging sessions, like [this one](https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/)

You can either do this for each shell instance like:
```shell
http_proxy="username:password@proxy_address:port" 
curl http://www.example.com

# you can skip the authentication part for an open proxy
```

or be smart guy, and export this and other relevant variables inside `.bashrc` (or maybe `.zshrc`) as
```
export http_proxy="http://$username:$password@$proxy_address:$port"
export HTTP_PROXY="http://$username:$password@$proxy_address:$port"
```
By other relavant variables, I mean
1. `https_proxy` / `HTTPS_PROXY`
2. `ftp_proxy` / `FTP_PROXY`
3. `no_proxy` / `NO_PROXY`
4. `rsync_proxy` / `RSYNC_PROXY`

To check if these variables have been set properly, you can run the following:
`set | grep -i proxy`
Similarly, these can be unset individually when required with `unset http_proxy`

**Bonus**
If you feel like all this is too much, you can use a tool like (ProxyMan)[https://github.com/himanshub16/ProxyMan/] that is a lightweight shell script with a simple interface to both set and unset these variables. 

This also does advanced steps like setting a proxy for commands like `apt update`, if you require. 
This is done by adding the following to `/etc/apt/apt.conf` 
```
Acquire::http::Proxy "http://username:password@proxy_address:port";
```

You can go even further with tools like [proxychains](https://github.com/haad/proxychains) that let you chain multiple proxies. This is used while setting up tor and comes pre-installed with pentesting distros like Kali and ParrotOS.

## 3. Using iptables <a name="iptables"></a>

Most general use cases will be satisfied by the above 2 steps. 
Even if you need to setup something like your own [man-in-the-middle proxy](https://docs.mitmproxy.org/stable/concepts-howmitmproxyworks/) like [mitm](https://mitmproxy.org/) or a [transparent proxy](https://www.imperva.com/learn/ddos/transparent-proxy/) like squid for simple logging, you could still use the previous step and launch apps from the terminal while setting the required variables to point to the proxy server 
That does, *mostly*, work.

But what if you want to send **all** of your system's traffic through your proxy? 
To setup a system wide proxy, most google searches will lead you to answers on stack-exchange that recommend some form of method #2. \
But, as stated in the [Gitlab blog](https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/) it does not always work, and is also a source of unwanted bugs.

> **Full disclaimer:** I haven't tried this properly myself and am also fairly new to using iptables. But, it seems like the only valid approach out there that tries to solve this specific problem
> I have kept my explanation; *based on my rudimentary understanding*; as short as possible
> **Please reference the post mentioned below for a better explanation**

`iptables` is a tool provided by [netfilter](https://www.netfilter.org/) that is used to configure custom firewalls on your system.

For our use case, we can mark all our out going network packets from a certain user and forward it to the process running our proxy.

Make sure that the proxy is running under a separate user, so as to prevent the proxy from intercepting its own output.

*Step-by-step instructions* - https://serverfault.com/a/674389/946308


# Some references online that helped me

1. https://unix.stackexchange.com/a/213740/428441
2. https://wiki.archlinux.org/title/Proxy_server
3. https://discourse.mitmproxy.org/t/transparent-proxying-on-a-single-machine-iptables/97
4. https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/