Operations 11 min read

Mastering Proxy Auto-Config (PAC): Seamlessly Manage Multiple Proxies for Development

This guide explains how to use Proxy Auto‑Config (PAC) files to intelligently route traffic through different proxy tools like ClashX, Whistle, and SwitchyOmega, covering the underlying JavaScript function, configuration examples, and a Node.js server for hot‑reloading the PAC file.

大转转FE
大转转FE
大转转FE
Mastering Proxy Auto-Config (PAC): Seamlessly Manage Multiple Proxies for Development

1. Daily Proxy Challenges

As a front‑end/back‑end/test engineer you may need VPN (e.g., ClashX) for scientific internet access, Whistle for local proxy during development, and other tools like Charles, Fiddler, mitmproxy for packet capture. Browser extensions such as SwitchyOmega let you switch proxy configurations on demand.

VPN (ClashX) for internet access

Whistle for local development proxy

Charles/Fiddler/mitmproxy for debugging

Browser extensions (SwitchyOmega) to toggle proxies

These tools usually set themselves as the system proxy, which is convenient but only one proxy can be active at a time, causing conflicts when multiple proxies are enabled.

Example: Running Whistle on port 8899 while ClashX is set as the system proxy. Using SwitchyOmega to route Chrome traffic through Whistle makes Google Search unavailable in Chrome, leading to workarounds such as opening a separate browser for search, manually switching SwitchyOmega profiles, or using its auto‑switch mode.

SwitchyOmega’s auto‑switch can direct internal domain traffic to Whistle and other traffic to VPN, but it only works within the current browser.

SwitchyOmega auto switch configuration
SwitchyOmega auto switch configuration

2. What is PAC?

PAC (Proxy Auto‑Config) is a mechanism supported by browsers and operating systems that uses a JavaScript function to decide whether a request should go directly or through a proxy.

A .pac file contains a JavaScript function that returns a proxy directive. The core function typically looks like:
function FindProxyForURL(url, host) {
  if (shExpMatch(host, "*.zhuanzhuan.com"))
    return "PROXY 127.0.0.1:8899"; // Whistle
  if (shExpMatch(host, "*.google.com"))
    return "PROXY 127.0.0.1:7890"; // Clash
  return "DIRECT";
}

The browser calls this function for each request and receives either a PROXY or DIRECT directive, allowing flexible routing without manual switching.

Who supports PAC?

SwitchyOmega can load a PAC file from a URL or a local script, but its effect is limited to the browser.

To apply a PAC file system‑wide, configure it in the OS network proxy settings. On macOS, this is done via System Settings → Wi‑Fi → Details → Proxy. macOS only supports loading PAC files from a server, while Windows supports both local and remote files.

macOS proxy settings screen
macOS proxy settings screen

3. Practical Example: Managing Multiple Proxies with PAC

The following example selects a proxy based on the domain and provides a fallback mechanism.

const DIRECT = 'DIRECT'; // direct connection
const DEFAULT = 'PROXY 127.0.0.1:7890; DIRECT'; // ClashX with fallback
const WHISTLE = 'PROXY 127.0.0.1:8899'; // Whistle for development

// Pattern rules (first match wins)
const config = [
  { proxy: DIRECT, pattern: /^::1$/ },               // local address
  { proxy: DIRECT, pattern: /^127\.0\.0\.1$/ },   // loopback
  { proxy: DIRECT, pattern: /^localhost$/ },       // localhost
  { proxy: WHISTLE, pattern: /\.caihuoxia\.com$/ }, // business domain
  { proxy: WHISTLE, pattern: /\.zhuanzhuan\.com$/ },
  { proxy: WHISTLE, pattern: /\.example\.com$/ }
];

function FindProxyForURL(url, host) {
  for (let i = 0; i < config.length; i++) {
    if (config[i].pattern.test(host)) {
      return config[i].proxy;
    }
  }
  return DEFAULT; // default policy if no rule matches
}

You can extend the rules to cover other proxy tools as needed, and PAC also provides built‑in helpers such as dnsDomainIs, shExpMatch, isInNet, etc.

4. Hosting the PAC File Locally with Hot Reload

To make the PAC file active, host it on a local HTTP server that supports hot reloading.

Example Node.js server:

const http = require('http');
const fs = require('fs');
const path = require('path');

const PAC_PATH = path.resolve(__dirname, './proxy.pac');
const PORT = 6001;
const HOST = '127.0.0.1';

let pacContent = '';

function loadPACFile() {
  try {
    pacContent = fs.readFileSync(PAC_PATH, 'utf8');
    console.log(`[PAC] Loaded ${PAC_PATH}`);
  } catch (err) {
    console.error('[PAC] Failed to load:', err.message);
  }
}

function watchPACFile() {
  fs.watch(PAC_PATH, (eventType) => {
    if (eventType === 'change') {
      console.log('[PAC] File changed, reloading...');
      loadPACFile();
    }
  });
}

function startServer() {
  http.createServer((req, res) => {
    if (req.url === '/proxy.pac') {
      res.writeHead(200, { 'Content-Type': 'application/x-ns-proxy-autoconfig' });
      res.end(pacContent);
    } else {
      res.writeHead(404, { 'Content-Type': 'text/plain' });
      res.end('Not Found');
    }
  }).listen(PORT, HOST, () => {
    console.log(`[PAC] Server running at http://${HOST}:${PORT}/proxy.pac`);
  });
}

loadPACFile();
watchPACFile();
startServer();

This server serves the PAC file and automatically reloads it when the file changes, making proxy adjustments instantaneous during development.

5. Summary

No manual switching: rules match automatically.

System‑wide effect: works for browsers, Postman, and other apps.

Dynamic proxy selection: logic can consider domain, path, or time.

Avoids proxy conflicts by centralizing rules.

Cross‑platform support: macOS and Windows natively handle PAC.

Using PAC transforms proxy management from a cumbersome manual task into an efficient, unified solution that boosts development productivity.

proxyAutomationNode.jsdevelopment toolsNetwork ConfigurationPAC
大转转FE
Written by

大转转FE

Regularly sharing the team's thoughts and insights on frontend development

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.