How to Set Up a Proxy in GitHub Actions

If you are trying to learn how to set up a proxy in GitHub Actions, start with one plain question: what should the proxy touch, and what should it leave alone? That answer decides whether you set variables for one step, one job, or the whole workflow. Get that wrong, and the runner will happily send traffic where you did not mean it to go.

GitHub Actions looks simple on the surface. A YAML file, a runner, a few commands. The trouble starts when a package download times out, a private registry refuses connection, or a security scan needs outbound access through a company proxy. Then the proxy becomes part of the workflow, not just a network detail.

1. Confirm the exact proxy scope for your workflow

Scope comes first because GitHub Actions is not one flat shell. A single workflow can contain 1 job, 5 steps, and several different network paths, and each one may need a different rule. A build step that fetches dependencies can go through the proxy while a deploy step to an internal host should bypass it.

Think in layers. If only one command needs the proxy, set it there. If every step in a job needs the proxy, define it at job level. If the entire workflow depends on it, place the variables at the workflow level, then keep a short list of exceptions in NO_PROXY. That sounds boring; it saves hours.

One practical example: a Node build may need the proxy for npm install, but a later step that posts to an internal webhook should not route through the same gateway. In that case, the proxy belongs in the build step or build job, not in the deployment step. One size rarely fits.

2. Store proxy settings as repository or organization secrets

Do not paste proxy credentials into workflow files. A proxy host and port may be harmless, but a username and password belong in GitHub Secrets or in environment-level variables that are protected the same way. Keep the YAML readable, and keep the secret material out of the commit history.

A neat pattern is to store a full proxy URL, or split values into separate secrets such as PROXY_HOST, PROXY_PORT, PROXY_USER, and PROXY_PASS. Either way, the workflow file stays short. That matters when five people later touch the same file and one of them is in a hurry.

Repository secrets are enough for one project. Organization secrets make more sense when several repositories use the same proxy policy, especially in a company with a shared CI network. For a broader comparison of privacy tools and proxy setups, see the VPN, proxy & privacy guides section.

3. Add proxy environment variables to a job or step

Most tools in GitHub Actions understand standard proxy variables. Use HTTP_PROXY, HTTPS_PROXY, and NO_PROXY, plus lowercase variants when a tool is picky. Some scripts read only uppercase names, while a few older libraries prefer lowercase. Set both if you want fewer surprises.

At job level, the variables apply to every step inside that job. At step level, they apply only to the command that follows. That distinction is easy to miss in a fast edit, and it creates the kind of failure where one package installs correctly while another one dies on the next line.

A clean job block often looks like this in practice: define the proxy in env, keep the credentials in secrets, and let commands inherit the environment. If one step should bypass the proxy, override the variable there instead of rewriting the whole job. Short, direct, and easier to review.

When you see a runner output that never mentions the proxy at all, check whether the tool actually reads environment variables. Some CLI tools do, some ignore them, and some require their own config file. The VPN and proxy glossary can help if you want the terms straight before you start changing settings.

4. Pass proxy settings to container-based jobs and services

Container jobs are a little different because the job runs inside the container, not directly on the runner host. In many cases, you need to duplicate the proxy variables inside the container environment, and sometimes the same is true for service containers. If you forget that step, the host can reach the proxy while the container cannot.

That difference matters in workflows that run databases, browsers, or test services alongside the main job. A database container might not need the proxy at all, but a test container that downloads a browser binary likely does. Keep the rule explicit, not implied.

There is also a practical catch with container images. If the image has its own package manager or bootstrap script, it may make outbound requests before your first workflow step runs. In that case, you need the proxy variables baked into the container definition, not added later in a shell command. Early traffic is still traffic.

5. Configure common package and tool setup inside Actions

Tool-specific setup is where many CI proxy problems hide. Node, npm, Python tooling, Git operations, curl, and language package managers can each behave differently. Some read the environment variables cleanly. Some prefer their own config. Some need both.

For Node workflows, package installation is usually the first test. If npm cannot reach the registry, check whether the proxy was set before the install step and whether the registry itself needs a separate configuration. The same goes for Python package installs that fail only after the first request. The proxy was there; the tool was not listening.

Git can be just as fussy. A checkout action may succeed while a later git fetch inside a script fails, especially if the script uses a different environment. A package manager in one step and a Git command in another are not the same client, so do not assume one setting covers both.

If your workflow depends on package access through a filtered network, it helps to read a focused guide like the how to choose a VPN article before you settle on the wider connectivity setup. The proxy is one piece; the route out of the runner is another.

6. Handle authenticated proxies and masked credentials

Authenticated proxies are common in corporate CI, and the URL often includes a username and password. Put those values in secrets, then assemble the URL at runtime instead of hardcoding it in the workflow file. One leak in a log is enough.

GitHub masks secrets in log output, but masking is not magic. If a script prints the full proxy URL in a debug line, or echoes environment values during a troubleshooting step, you may expose more than you intended. Keep debug output narrow, and avoid dumping every variable just to see one value.

A better habit is to test with a harmless command first, such as a package query or a metadata request, and confirm that the command succeeds without printing the proxy itself. If the proxy needs authentication, use the proxy authentication best practices guide for safer handling before you embed anything in CI.

One small warning: if you place credentials in a repository secret and then reuse that secret across multiple jobs, every job that can read the secret can also send traffic through the proxy. That is normal, but it should be deliberate. A proxy credential is still a credential.

7. Exclude internal hosts and GitHub endpoints with NO_PROXY

NO_PROXY is the part people postpone until something breaks. Then they add one host, test again, and find another host that should have been excluded from the start. List localhost, loopback addresses, internal domains, and any service names that must stay direct. That list is usually longer than expected.

GitHub-related endpoints can also need special handling. Some workflows must reach GitHub services directly, while other requests should travel through the proxy. If you send everything through the proxy without checking, you may create slow checkouts, webhook delays, or unexpected certificate complaints. The proxy is not always the right path.

Internal names deserve care because they are often different from public names by just one suffix. A build server might be reachable as build.local on the internal network and completely unusable through the proxy. Put that host in NO_PROXY rather than hoping DNS will sort it out for you.

If you want a deeper look at bypass rules, see how to hide your IP address for the logic behind which requests should stay direct and which should not. The same habit of separating internal and external traffic applies here, just in a CI context.

8. Test the workflow and troubleshoot proxy failures

Test with one small step before you trust the whole workflow. A simple download, a version check, or a header request tells you more than a long build log. If that step fails, do not change three settings at once. Change one, run again, and watch the result.

Timeouts usually point to a routing problem, a blocked destination, or a proxy address that the runner cannot reach. Certificate errors often mean the proxy is intercepting TLS and the runner does not trust the issuing chain. Package failures can mean the proxy is fine but the tool is ignoring the environment variables. Each failure has a different smell.

It also helps to separate proxy failure from runner limits. GitHub-hosted runners have network rules you cannot change, and self-hosted runners can have firewall rules that look like proxy trouble from the outside. If one runner works and another fails on the same workflow, the proxy may not be the cause at all.

For a fast sanity check, verify the outbound address after the workflow runs. If you need a checklist for that, the article on how to verify your IP is still a useful model, even though the setting is different. Numbers, endpoints, and response codes tell the story better than guesses do.

When you compare failure modes, keep one rule: if the error appears before the first network call, look at YAML and secrets; if it appears during a package fetch, look at proxy variables and tool config; if it appears only on one host, look at NO_PROXY and DNS. That three-way split saves time. And yes, it saves a lot of time.