"The host uses this PAC file, so I put the same URL in the VM" is a reasonable sentence and an incomplete plan. A PAC URL points at a policy script, not at a proxy. Until the guest can fetch that script, evaluate it with the guest's own addresses and then reach whatever proxy the script names, the URL is a string in a settings field. Most of the confusion around proxy policy in virtual machines comes from treating that one line as the whole configuration.

A PAC URL is a script, not a proxy

The file contains a function that takes a URL and a host and returns a proxy description or the word DIRECT. Nothing in the URL tells the application where to send traffic; that decision happens at runtime, inside the script, using data the script asks the platform for. A settings dialog that accepts a PAC URL is accepting a pointer to a decision procedure.

That distinction is why copying the URL can look like it worked. The field is populated, the setting is saved, and the failure only appears later, when the script cannot be fetched or when it returns a proxy the guest cannot reach.

The four steps each fail differently

Inside the guest, four things have to happen in order, and each one has its own error signature. The guest retrieves the PAC file. The application evaluates the script for the requested URL using local information. The selected proxy is resolved and reached. Authentication happens if the proxy requires it.

Start by proving the retrieval, because everything downstream is meaningless without it. A PAC file on a private server requires a permitted path to that server before any rule can help, and a proxy choice inside an unreachable script cannot create the path that would fetch it:

curl -sS -o /dev/null -w '%{http_code}\n' http://pac.corp.example/proxy.pac
getent hosts pac.corp.example

If that request fails from the guest and works from the host, the problem is the guest's path to the PAC server, not the script's contents. If it returns a JavaScript file, move to the second step and find out what the script decides for the guest's context.

The same script decides differently inside a VM

PAC functions can inspect the requested host and information about the machine running the evaluation. A rule built on the client's own address, for example one that checks an interface address or a subnet membership test, will see the guest's address rather than the physical host's. Behind host-side NAT those are different addresses, and the same script can therefore select a different proxy or fall back to DIRECT inside the VM.

That is not a bug in the script. It is the script doing exactly what it was written to do with a different input, and it explains the confusing report where the host uses the proxy and the guest connects directly. Reproduce the decision rather than reasoning about it: a PAC evaluator that takes an address and a URL, if your distribution packages one, settles the question in one command. Otherwise test with the application that will really be used, and read its proxy log instead of guessing.

Do not conclude that the guest inherited the host's proxy settings because its traffic passes through host-side translation. Network translation forwards packets; it does not copy application configuration, and the system proxy is application configuration.

Tools that never read PAC at all

Command-line tools are a separate boundary, and this is where a lot of time is lost. curl does not execute PAC files, as its proxy documentation states plainly. Pointing a proxy variable at the PAC download URL does not turn the script into a proxy endpoint; the tool will try to speak HTTP to a JavaScript file and fail in a way that looks like a network problem.

The same applies to many package managers, language runtimes and build tools, which honour explicit proxy variables or their own configuration and nothing else. If the test you care about is a CLI tool, configure it with the concrete proxy that the PAC script would have chosen, and record how you derived that choice so the next person can redo it.

For desktop applications on Linux, the system setting has to be set to automatic mode as well as given a URL; a URL saved while the mode is still manual does nothing. Check both, and check them inside the guest:

gsettings get org.gnome.system.proxy mode
gsettings get org.gnome.system.proxy autoconfig-url

DIRECT is a decision too

A PAC result of DIRECT means the application bypasses the HTTP proxy, not that it has escaped the network. The resulting connection can still follow an operating-system route through a tunnel, or fail for reasons that have nothing to do with proxying. Conversely, a proxy result describes one application's request, not every process in the guest.

So verify in the direction the requirement was written. If the requirement is "this application reaches the internal site", prove that application does, and note which proxy or route carried it. If the requirement is "the VM is on the corporate network", a working browser through a selected proxy is evidence for that browser and nothing more.

Fix the chain inside the guest rather than switching off the host's tunnel or relaxing forwarding policy to make a test pass. The chain has four links, and a change that skips one of them will hold until the next time the script is updated or the guest's address changes.

Makomi ya ndenge moko