A Beginner’s Guide to Proxy Auto Config (PAC) for DevelopersProxy Auto Config (PAC) files are a simple but powerful tool for controlling how browsers and other HTTP clients choose proxies for different destinations. For developers, understanding PAC files helps with debugging network behavior, implementing granular routing rules, and supporting complex corporate or testing environments. This guide explains what PAC files are, why they matter, how they work, and how to write, test, and deploy them effectively.
What is a PAC file?
A PAC file is a JavaScript file that defines a single function, FindProxyForURL(url, host). When a browser or client is configured to use a PAC file, it calls this function for each request. The function returns a string that tells the client which proxy (or direct connection) to use.
- Format: JavaScript
- Function name: FindProxyForURL(url, host)
- Return value: A proxy string like “PROXY proxy.example.com:8080” or “DIRECT”, or a sequence like “PROXY p1:8080; PROXY p2:8080; DIRECT”.
Why developers should care
- Debugging: PAC files can reveal why certain traffic goes through a proxy or bypasses it, helping diagnose issues with authentication, caching, or access.
- Testing and staging: Route only specific hosts to staging environments or local proxies without changing system-wide proxy settings.
- Performance: Bypass proxies for local or performance-sensitive hosts to reduce latency.
- Security and compliance: Force traffic for certain domains through monitoring or filtering proxies.
Anatomy of FindProxyForURL
The function signature:
function FindProxyForURL(url, host) { // logic here return "DIRECT"; }
- url: full URL (e.g., “http://example.com/path”)
- host: hostname portion (e.g., “example.com”)
Return values (can be chained with semicolons):
- “DIRECT” — connect without a proxy.
- “PROXY host:port” — use an HTTP proxy.
- “SOCKS host:port” or “SOCKS5 host:port” — use a SOCKS proxy.
- Multiple entries allow fallback (try first, then next).
Useful built-in PAC helper functions
PAC environment provides multiple helper functions to simplify rules. Common ones:
- dnsDomainIs(host, domain) — true if host ends with domain
- shExpMatch(str, shexp) — wildcard matching (e.g., “*.example.com”)
- isInNet(ipaddr, pattern, mask) — match IPv4 address ranges
- dnsResolve(host) — resolve hostname to IP (may return null)
- myIpAddress() — get client IP address
- weekdayRange(), dateRange(), timeRange() — schedule-based rules
Example usages:
if (dnsDomainIs(host, ".internal.example.com")) return "DIRECT"; if (shExpMatch(url, "https://*.staging.example.com/*")) return "PROXY staging-proxy:8080";
Common patterns and examples
- Bypass local network and internal domains:
function FindProxyForURL(url, host) { // Local names if (shExpMatch(host, "*.local") || host.indexOf(".") == -1) return "DIRECT"; // Internal domain if (dnsDomainIs(host, ".internal.example.com")) return "DIRECT"; // Default proxy return "PROXY proxy.example.com:3128; DIRECT"; }
- Use a proxy for all HTTP, direct for HTTPS (not recommended for security, shown for pattern):
function FindProxyForURL(url, host) { if (url.substring(0, 5) == "http:") return "PROXY proxy.example.com:8080"; return "DIRECT"; }
- Geo/IP-based logic (using DNS resolution + isInNet — note DNS-based geolocation is limited):
function FindProxyForURL(url, host) { var ip = dnsResolve(host); if (ip && isInNet(ip, "10.0.0.0", "255.0.0.0")) return "DIRECT"; return "PROXY proxy.example.com:3128; DIRECT"; }
- Failover proxies:
function FindProxyForURL(url, host) { return "PROXY p1.example.com:8080; PROXY p2.example.com:8080; DIRECT"; }
Testing PAC files locally
- Browser testing: Set browser to use “Automatic proxy configuration” and provide a file:// or http:// URL pointing to your PAC file.
- Tools:
- curl: not native support for PAC; use proxy specification directly or tools that evaluate PAC.
- pacparser (library/CLI) — evaluate PAC files programmatically.
- Online PAC testers (for quick checks).
- Chrome: Developer Tools > Network tab will show proxy used; chrome://net-internals can help diagnose (may vary by Chrome version).
- Firefox: about:config, set network.proxy.autoconfig_url and use about:networking for diagnostics.
Security considerations
- PAC files are JavaScript — they can include any logic but run in a restricted environment. Avoid hosting PAC files on untrusted servers; clients automatically fetch them and will execute the logic.
- If the PAC file is served over HTTP, it can be tampered with. Serve PAC files over HTTPS and use strong hosting controls.
- Avoid embedding sensitive credentials or secrets in PAC logic.
- Beware of DNS-based logic: dnsResolve can leak DNS queries and may be manipulated by poisoned DNS.
Performance and caching
- Browsers cache PAC files, but refresh frequency varies. Use appropriate cache headers when serving PAC files.
- Complex PAC logic (heavy DNS resolves, loops) can slow down request resolution. Keep FindProxyForURL efficient.
- Prefer simple pattern matching with shExpMatch and dnsDomainIs over frequent dnsResolve calls.
Deployment tips
- Host PAC on a reliable, fast server (HTTPS preferred).
- Use versioned filenames or query strings to force client refresh after updates (e.g., proxy.pac?v=20250901).
- Test on all target client platforms (Windows group policy, macOS network settings, Linux desktop environments, mobile browsers) because behavior can differ.
- For managed environments, deploy via:
- WPAD (Web Proxy Auto-Discovery) — has security considerations (risk of rogue WPAD servers).
- Group Policy (Windows) to set PAC URL.
- Mobile device management (MDM) solutions for iOS/Android.
Debugging tips
- Simplify: Reduce rules to a minimal case that reproduces the issue.
- Add logging via temporary modifications: e.g., return distinct proxy strings for branches and observe which is chosen.
- Use pacparser to run unit tests against a list of URLs/hosts.
- Check HTTP response headers for caching and MIME type (should be application/x-ns-proxy-autoconfig or text/plain).
- Confirm PAC file URL is reachable and served with correct headers and status.
Common pitfalls
- Relying on DNS resolution ordering — dnsResolve may block or fail.
- Assuming consistent behavior across browsers/OSes — test widely.
- Using long-running or blocking calls (e.g., lots of DNS lookups) inside FindProxyForURL.
- Exposing PAC file over HTTP (man-in-the-middle risk).
- Improper MIME type causing some clients to ignore the PAC.
Advanced topics (brief)
- Generating PAC files dynamically server-side based on user, location, or device.
- Integrating PAC with PAC-over-HTTPS (proxy auto-config delivered via HTTPS APIs).
- Combining PAC with SD-WAN or split-tunnel VPN logic.
- Using pacparser in CI to validate PAC changes before deployment.
Example full PAC file (comprehensive)
function FindProxyForURL(url, host) { // local hostnames (no dots) and .local TLD if (host.indexOf(".") == -1 || shExpMatch(host, "*.local")) return "DIRECT"; // Internal networks if (dnsDomainIs(host, ".internal.example.com")) return "DIRECT"; if (isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0")) return "DIRECT"; // Special staging hosts if (shExpMatch(host, "*.staging.example.com")) return "PROXY staging-proxy.example.com:8080"; // Default with failover return "PROXY proxy1.example.com:3128; PROXY proxy2.example.com:3128; DIRECT"; }
Conclusion
PAC files are a lightweight, flexible way to control proxy selection per request. For developers, mastering PAC scripting improves debugging, testing, and deployment of network routing rules. Keep PAC logic simple and fast, secure the PAC file distribution, and test across platforms to ensure consistent behavior.
Leave a Reply