Post

How to force proxy for some domains/applications using PAC file on MacOS - Linux

In this post, I explain how I force selected domains and softwares to be passed through my proxy tunnel using pac file on MacOS (Linux too)

How to force proxy for some domains/applications using PAC file on MacOS - Linux

Hi there

Again me, faced another problem and I’m here to share my way to overcome this problem

Situation explained

Let me tell you…

Islamic Republic blocks different websites and several here and then; Discord is one of them.

Several month ago, I decided to find a solution to force my Discord app to use my proxy server (its local, by Clash or V2ray), I couldn’t find a proper way…

Today, I decided to do the same with several apps…. This ended up finding a solution for an old problem!

Solution

I signed up for Deepseek today 😂 and I decided to use it a little bit.

After searching, reading, testing, struggling and so on, I found out my solution is in learning .pac file! (Notion AI help me 👇)

A PAC (Proxy Auto-Configuration) file is a JavaScript file that defines how web browsers and other user agents can automatically choose the appropriate proxy server for fetching a given URL. When implemented, a PAC file contains a JavaScript function called FindProxyForURL that determines whether requests should go directly to the destination or be forwarded to a proxy server. This functionality allows network administrators to implement sophisticated rules for routing traffic, such as using different proxies for internal versus external websites, or bypassing the proxy for specific domains. PAC files provide a flexible and efficient way to manage proxy settings across an organization or for individual use.

Setup

Okay…

I got a .pac file content but it had a problem SOCKS5 127.0.0.1:2888 instead of SOCKS 127.0.0.1:2888

Then I found out MacOS does NOT support .pac file as file (instead of URL), so I have to load a python simple http server on localhost to serve the .pac file

On the other hand, I had to make my local http server load automatically and reload on failure. For this purpose I know systemd and its alternative in Linux, BUT MacOS? its my first time

After searching I realized MacOS’s LaunchAgents is the exact stuff I want!, so I tried to set it up

.pac file + a local http server

create a notion-proxy.pac file:

1
2
3
4
5
6
7
8
9
10
function FindProxyForURL(url, host) {
    // Check if the host is a Notion URL
    if (shExpMatch(host, "*.example.com") || shExpMatch(host, "*.example.net") || shExpMatch(host, "*discord*") || dnsDomainIs(host, "check-host.net") || shExpMatch(host, "facebook.com") || dnsDomainIs(host, "discordapp.net")) {
        // Proxy all Notion URLs through the SOCKS5 proxy
        return "SOCKS 127.0.0.1:9999";
    }

    // Direct connection for all other URLs
    return "DIRECT";
}

⚠️ You have to edit this file to seperate the tunneling process (the third line) if (shExpMatch(host, "*.example.com") || shExpMatch(host, "*discord*") || dnsDomainIs(host, "check-host.net")) { To find out more, google ‘.pac structure’

Then a pac.sh file (bash script) to run the server

1
2
3
#!/bin/bash

python3 -m http.server -b 127.0.0.1 -d /path/to/pac/folder/ 1234

For security, I prefer to bind it to localhost

setup LaunchAgents for automation

Now, its time for LaunchAgents :

⚠️ Linux users, go with systemd, initd or any other alternative

create a file using this command:

1
nano ~/Library/LaunchAgents/com.run.pac.server.plist

and its content is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- A unique identifier for the agent -->
    <key>Label</key>
    <string>com.run.pac.server</string>

    <!-- Path to the script to run -->
    <key>Program</key>
    <string>/Library/Scripts/pac.sh</string>

    <!-- Run the script at load -->
    <key>RunAtLoad</key>
    <true/>

    <!-- Keep the job alive, restart on failure -->
    <key>KeepAlive</key>
    <true/>

    <!-- Optional: Redirect stdout and stderr to log files -->
    <key>StandardOutPath</key>
    <string>/path/to/pac/folder/pac.log</string>
    <key>StandardErrorPath</key>
    <string>/path/to/pac/folder/pac-error.log</string>

    <!-- Optional: Environment variables -->
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
</dict>
</plist>

Load this agent and then start it is not:

1
2
3
launchctl load ~/Library/LaunchAgents/com.run.pac.server.plist

launchctl start com.run.pac.server

Now, http://127.0.0.1:1234/notion-proxy.pac is your PAC file address which you have to enter in “Network interface (Wifi, VPN, Lan, etc.) -> proxies -> Automatic proxy configuration ✔”

👋 Good Luck and text me for helping or asking

This post is licensed under CC BY 4.0 by the author.