When automating deployment and testing, there is often a need to use proxy servers in CI/CD processes. This may be due to corporate security policies, testing geolocation features, or bypassing rate-limiting when downloading dependencies. In this guide, we will explore practical proxy configuration for popular CI/CD platforms with ready-made configuration examples.
Why Use Proxies in CI/CD Processes
Using proxy servers in automated deployment processes addresses several critical tasks. First, many corporate networks require all outgoing traffic to pass through corporate proxies for security control and logging. Without proper configuration, the CI/CD pipeline simply won't be able to download dependencies or connect to external services.
Secondly, when testing applications with geolocation logic, it is necessary to verify functionality from different countries. For example, if you are developing a service with regional content or pricing, automated tests must simulate users from various locations. Residential proxies with IP addresses from the required regions are helpful here.
The third reason is to bypass rate-limiting and blocks. With frequent pipeline runs, especially in large teams, CI/CD servers may fall under the API limits of external services. For example, the GitHub API or package registries may temporarily block IPs when the request limit is exceeded. Proxy rotation helps distribute the load.
Important: Connection stability is critical for CI/CD processes. Use proxies with an uptime of at least 99.5% and a fast response (less than 200ms). Unstable proxies will lead to random build failures and waste the team's time on investigations.
Configuring Proxy in GitHub Actions
GitHub Actions is one of the most popular platforms for CI/CD. Proxy configuration here is done through environment variables, which can be set at the workflow or organization level. Let's consider several integration methods.
Basic Configuration via Environment Variables
The simplest way is to set the HTTP_PROXY and HTTPS_PROXY environment variables at the beginning of the job. Most tools (curl, wget, npm, pip) automatically use these variables:
name: CI with Proxy
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: localhost,127.0.0.1,.internal.domain
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
The NO_PROXY variable is critically importantβit excludes local addresses and internal services from proxying. Without it, there may be issues connecting to localhost or internal Docker containers.
Secure Storage of Credentials via GitHub Secrets
If the proxy requires authentication, never store the username and password in plain text in the workflow file. Use GitHub Secrets:
name: CI with Authenticated Proxy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure Proxy
run: |
echo "HTTP_PROXY=http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}" >> $GITHUB_ENV
echo "HTTPS_PROXY=http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}" >> $GITHUB_ENV
echo "NO_PROXY=localhost,127.0.0.1" >> $GITHUB_ENV
- name: Test proxy connection
run: curl -I https://api.github.com
- name: Install dependencies
run: npm ci
Create secrets in the repository settings: Settings β Secrets and variables β Actions β New repository secret. Add PROXY_USER, PROXY_PASS, PROXY_HOST, and PROXY_PORT. These values will be encrypted and not available in the logs.
Configuring Proxy for Specific Steps
Sometimes you need to use a proxy only for specific operations, for example, only for downloading dependencies but not for deployment. Set the variables at the specific step level:
steps:
- name: Download dependencies via proxy
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
run: npm install
- name: Deploy without proxy
run: ./deploy.sh
Integrating Proxy with GitLab CI/CD
GitLab CI/CD provides several levels of proxy configuration: at the runner level, project level, and specific job level. The choice depends on whether the proxy is needed for all projects or just for specific ones.
Configuring Proxy at the GitLab Runner Level
If you are using a self-hosted GitLab Runner and all projects must work through a proxy, configure it in the runner configuration. Edit the file /etc/gitlab-runner/config.toml:
[[runners]]
name = "docker-runner"
url = "https://gitlab.com/"
token = "YOUR_TOKEN"
executor = "docker"
[runners.docker]
image = "alpine:latest"
privileged = false
[runners.docker.services_environment]
HTTP_PROXY = "http://proxy.example.com:8080"
HTTPS_PROXY = "http://proxy.example.com:8080"
NO_PROXY = "localhost,127.0.0.1,.gitlab.com"
After changing the configuration, restart the runner: sudo gitlab-runner restart. Now all jobs on this runner will automatically use the proxy.
Configuring via .gitlab-ci.yml
To configure the proxy at the specific project level, use variables in the .gitlab-ci.yml file. This is a more flexible approach, allowing different projects to use different proxies:
variables:
HTTP_PROXY: "http://proxy.example.com:8080"
HTTPS_PROXY: "http://proxy.example.com:8080"
NO_PROXY: "localhost,127.0.0.1,.internal"
stages:
- build
- test
- deploy
build:
stage: build
script:
- echo "Proxy configured: $HTTP_PROXY"
- npm install
- npm run build
artifacts:
paths:
- dist/
test:
stage: test
script:
- npm test
dependencies:
- build
Using GitLab CI/CD Variables for Credentials
For storing sensitive data, use CI/CD Variables in the project settings: Settings β CI/CD β Variables. Create protected and masked variables:
- PROXY_URL β full URL with credentials (masked)
- PROXY_HOST β proxy server host
- PROXY_PORT β port
- PROXY_USER and PROXY_PASS β for separate storage
Then use them in .gitlab-ci.yml:
build:
stage: build
before_script:
- export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
- export HTTPS_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
script:
- npm install
- npm run build
Proxy Configuration in Jenkins
Jenkins offers several ways to configure proxies depending on the architecture: global settings for Jenkins master, settings for specific agents, or settings at the individual pipeline level.
Global Proxy Settings for Jenkins
To configure the proxy that Jenkins will use for plugin updates and other internal operations, go to Manage Jenkins β Manage Plugins β Advanced. In the HTTP Proxy Configuration section, specify:
- Server: proxy.example.com
- Port: 8080
- Username and Password (if authentication is required)
- No Proxy Host: localhost,127.0.0.1,.internal
This setting only affects Jenkins itself, not the jobs. A separate configuration is needed for jobs.
Configuring Proxy for Jenkins Pipeline
In the Jenkinsfile, you can set environment variables for the entire pipeline or for specific stages:
pipeline {
agent any
environment {
HTTP_PROXY = 'http://proxy.example.com:8080'
HTTPS_PROXY = 'http://proxy.example.com:8080'
NO_PROXY = 'localhost,127.0.0.1,.internal'
}
stages {
stage('Build') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}
Using Jenkins Credentials for Proxy
For secure storage of proxy credentials, use the Jenkins Credentials Store. Create credentials of type "Username with password" in Manage Jenkins β Manage Credentials, then use them in the pipeline:
pipeline {
agent any
stages {
stage('Build with Authenticated Proxy') {
steps {
withCredentials([usernamePassword(
credentialsId: 'proxy-credentials',
usernameVariable: 'PROXY_USER',
passwordVariable: 'PROXY_PASS'
)]) {
sh '''
export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:8080"
export HTTPS_PROXY="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:8080"
npm install
'''
}
}
}
}
}
Configuring Proxy for Jenkins Agents
If you are using separate Jenkins agents (nodes), configure the proxy for each agent individually. In the agent configuration (Manage Jenkins β Manage Nodes β Configure), add to Environment variables:
HTTP_PROXY=http://proxy.example.com:8080
HTTPS_PROXY=http://proxy.example.com:8080
NO_PROXY=localhost,127.0.0.1
Proxy for Docker in CI/CD
Docker is an integral part of modern CI/CD processes. Configuring a proxy for Docker has its own peculiarities, as you need to set up the proxy for both the Docker daemon and the containers.
Configuring Proxy for Docker Daemon
To allow the Docker daemon to download images through a proxy, create a systemd drop-in file. On a Linux system, create a directory and file:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
Add the following content:
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"
Environment="HTTPS_PROXY=http://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,.internal,docker.io"
Reload the configuration and Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
Proxy for Containers During Build
If containers need access through a proxy during the build (for example, to install packages), pass the variables through build args in the Dockerfile:
FROM node:18-alpine
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ENV HTTP_PROXY=${HTTP_PROXY}
ENV HTTPS_PROXY=${HTTPS_PROXY}
ENV NO_PROXY=${NO_PROXY}
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# Remove proxy variables for runtime
ENV HTTP_PROXY=
ENV HTTPS_PROXY=
CMD ["npm", "start"]
In the CI/CD pipeline, pass build args:
# GitHub Actions
- name: Build Docker image with proxy
run: |
docker build \
--build-arg HTTP_PROXY=${{ secrets.PROXY_URL }} \
--build-arg HTTPS_PROXY=${{ secrets.PROXY_URL }} \
--build-arg NO_PROXY=localhost,127.0.0.1 \
-t myapp:latest .
# GitLab CI
docker build:
script:
- docker build
--build-arg HTTP_PROXY="${PROXY_URL}"
--build-arg HTTPS_PROXY="${PROXY_URL}"
-t myapp:latest .
Docker Compose with Proxy
When using Docker Compose in CI/CD, configure the proxy via environment in docker-compose.yml:
version: '3.8'
services:
app:
build:
context: .
args:
- HTTP_PROXY=${HTTP_PROXY}
- HTTPS_PROXY=${HTTPS_PROXY}
environment:
- HTTP_PROXY=${HTTP_PROXY}
- HTTPS_PROXY=${HTTPS_PROXY}
- NO_PROXY=localhost,127.0.0.1
ports:
- "3000:3000"
Configuring Proxy for Package Managers
Package managers often require additional proxy configuration, especially if they use their own configuration files. Let's consider the setup for popular package managers.
NPM and Yarn
NPM can use both the HTTP_PROXY/HTTPS_PROXY environment variables and its own configuration. For explicit configuration in CI/CD:
# In GitHub Actions or GitLab CI
- name: Configure npm proxy
run: |
npm config set proxy http://proxy.example.com:8080
npm config set https-proxy http://proxy.example.com:8080
npm config set noproxy "localhost,127.0.0.1"
- name: Install dependencies
run: npm install
# For Yarn
- name: Configure yarn proxy
run: |
yarn config set proxy http://proxy.example.com:8080
yarn config set https-proxy http://proxy.example.com:8080
An alternative way is to create a .npmrc file at the root of the project (but do not commit credentials!):
# .npmrc (generated in CI)
proxy=http://proxy.example.com:8080
https-proxy=http://proxy.example.com:8080
noproxy=localhost,127.0.0.1
Python pip and Poetry
Pip uses environment variables, but can also be configured through settings:
# Through environment variables (recommended for CI)
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
pip install -r requirements.txt
# Or through pip parameters
pip install --proxy http://proxy.example.com:8080 -r requirements.txt
# For Poetry
poetry config http-basic.proxy http://proxy.example.com:8080
poetry install
Maven and Gradle
For Java projects, proxy configuration requires creating configuration files. For Maven, create settings.xml in the CI pipeline:
- name: Configure Maven proxy
run: |
mkdir -p ~/.m2
cat > ~/.m2/settings.xml << EOF
<settings>
<proxies>
<proxy>
<id>http-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
</proxies>
</settings>
EOF
- name: Build with Maven
run: mvn clean install
For Gradle, add settings to gradle.properties:
systemProp.http.proxyHost=proxy.example.com
systemProp.http.proxyPort=8080
systemProp.https.proxyHost=proxy.example.com
systemProp.https.proxyPort=8080
systemProp.http.nonProxyHosts=localhost|127.0.0.1
Secure Storage of Proxy Credentials
Storing proxy credentials is a critical aspect of CI/CD security. A leak of this data can lead to unauthorized use of the proxy and financial losses. Let's consider best practices for different platforms.
GitHub Actions Secrets
GitHub Actions offers three levels of secrets: repository, environment, and organization. For proxy credentials, use:
- Repository secrets β for projects where the proxy is needed only in one repository
- Organization secrets β if one proxy is used across all projects in the organization
- Environment secrets β for different proxies in staging/production environments
Important security rules:
- Never output secrets in logs: GitHub automatically masks them, but it's better to avoid echo
- Use different credentials for different environments
- Regularly rotate proxy passwords (at least once every 90 days)
- Restrict access to secrets through branch protection rules
GitLab CI/CD Variables
GitLab offers additional options for protecting variables:
- Protected β the variable is available only in protected branches (main, production)
- Masked β the value is automatically hidden in logs
- Environment scope β restricting use to specific environments
Recommended configuration for proxy credentials:
# Settings β CI/CD β Variables
PROXY_USER: myuser (Protected: Yes, Masked: Yes)
PROXY_PASS: secret123 (Protected: Yes, Masked: Yes)
PROXY_HOST: proxy.example.com (Protected: No, Masked: No)
PROXY_PORT: 8080 (Protected: No, Masked: No)
Jenkins Credentials Store
The Jenkins Credentials Store supports several types of credential storage. For proxies, it is recommended to:
- Use "Username with password" for proxy login/password
- Set up Folder-level credentials for different teams/projects
- Enable the Credentials Binding Plugin for secure use in Pipeline
- Set up audit logging to track credential usage
External Secret Management Systems
For enterprise environments, it is recommended to use specialized secret management systems: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or Google Secret Manager. Hereβs an example of integration with HashiCorp Vault in GitHub Actions:
- name: Import Secrets from Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/proxy proxy_user | PROXY_USER ;
secret/data/proxy proxy_pass | PROXY_PASS ;
secret/data/proxy proxy_host | PROXY_HOST
- name: Configure Proxy
run: |
export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:8080"
npm install
Troubleshooting Common Issues
When integrating proxies into CI/CD, the same issues often arise. Let's look at the most common ones and how to resolve them.
Issue: Connection Timeout When Downloading Dependencies
Symptoms: npm install, pip install, or docker pull fail with a timeout error after 30-60 seconds.
Causes:
- The proxy server is unavailable or overloaded
- Incorrect proxy URL format (forgot http:// at the beginning)
- The proxy requires authentication, but credentials are not provided
- Firewall blocks the connection from the CI/CD runner to the proxy
Solution:
# 1. Check proxy availability
- name: Test proxy connectivity
run: |
curl -v -x http://proxy.example.com:8080 https://www.google.com
echo "Proxy test completed"
# 2. Increase timeout for npm
- name: Install with increased timeout
run: |
npm config set fetch-timeout 300000
npm install
# 3. Check URL format
- name: Debug proxy configuration
run: |
echo "HTTP_PROXY: $HTTP_PROXY"
echo "HTTPS_PROXY: $HTTPS_PROXY"
# Should be: http://user:pass@host:port
Issue: SSL Certificate Verification Failed
Symptoms: Errors like "SSL certificate problem: unable to get local issuer certificate" or "CERT_UNTRUSTED".
Cause: Corporate proxies often perform SSL inspection, replacing certificates. The CI/CD runner does not trust the corporate CA.
Solution:
# Option 1: Add corporate CA certificate
- name: Install corporate CA certificate
run: |
sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# Option 2: Disable SSL verification (NOT recommended for production!)
- name: Install with SSL verification disabled
run: |
npm config set strict-ssl false
npm install
env:
NODE_TLS_REJECT_UNAUTHORIZED: 0
# Option 3: Use proxy only for HTTP, HTTPS directly
- name: Selective proxy usage
run: npm install
env:
HTTP_PROXY: http://proxy.example.com:8080
# Do not set HTTPS_PROXY
Warning: Disabling SSL certificate verification creates serious security risks. Use this approach only for internal corporate networks and ensure to add the corporate CA to trusted ones.
Issue: Proxy Works for Some Commands but Not Others
Symptoms: npm install works through the proxy, but git clone or docker pull ignore proxy settings.
Cause: Different tools use different proxy configuration mechanisms. Git and Docker have their own configuration files.
Solution:
# Configure Git proxy
- name: Configure Git proxy
run: |
git config --global http.proxy http://proxy.example.com:8080
git config --global https.proxy http://proxy.example.com:8080
# Configure Docker proxy (see Docker section above)
# For wget/curl
- name: Configure wget/curl
run: |
echo "use_proxy = on" >> ~/.wgetrc
echo "http_proxy = http://proxy.example.com:8080" >> ~/.wgetrc
echo "https_proxy = http://proxy.example.com:8080" >> ~/.wgetrc
Issue: Internal Services Unavailable When Proxy is Enabled
Symptoms: After configuring the proxy, connections to localhost, internal Docker containers, or corporate services stopped working.
Cause: The NO_PROXY variable is incorrectly configured, causing all requests to go through the proxy, including local ones.
Solution:
# Correct NO_PROXY configuration
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: |
localhost,
127.0.0.1,
0.0.0.0,
.internal,
.local,
.corp.example.com,
docker.internal,
host.docker.internal
# For Docker Compose, also add
services:
app:
environment:
- NO_PROXY=localhost,127.0.0.1,db,redis
# db and redis are names of other services in compose
Issue: Proxy Credentials Appear in Logs
Symptoms: Proxy passwords are visible in plain text in CI/CD logs.
Cause: Outputting environment variables via echo or verbose command modes.
Solution:
# β BAD - credentials in logs
- name: Debug proxy
run: |
echo "Proxy: $HTTP_PROXY" # Will show http://user:pass@host:port
curl -v ... # Verbose mode shows credentials
# β
GOOD - safe output
- name: Debug proxy (safe)
run: |
echo "Proxy host configured: $(echo $HTTP_PROXY | cut -d'@' -f2)"
# Will show only host:port
# Use secrets for masking
- name: Configure proxy
env:
PROXY_URL: ${{ secrets.PROXY_URL }} # GitHub automatically masks
run: |
export HTTP_PROXY="$PROXY_URL"
Conclusion
Integrating a proxy into the CI/CD pipeline is an important aspect of automation that ensures security, compliance with corporate policies, and the ability to test geolocation features. In this guide, we explored practical ways to configure proxies for GitHub Actions, GitLab CI, Jenkins, Docker, and popular package managers.
Key points to remember when configuring proxies in CI/CD: always use secure storage for credentials through built-in secret mechanisms of the platforms, properly configure NO_PROXY to exclude local and internal services, test the connection to the proxy before main operations, and monitor logs for sensitive data leaks. For critical production environments, it is recommended to use external secret management systems like HashiCorp Vault.
The choice of proxy type depends on your tasks: corporate networks typically use existing HTTP/HTTPS proxies, residential proxies with IPs from required countries are suitable for testing geolocation features, and data center proxies can be used for high-speed dependency downloads. It is important to ensure high uptime of proxy servers, as their unavailability will lead to failures of all builds and block the development team's work.
When issues arise, start by checking the basic availability of the proxy using curl or wget, then verify the correctness of the URL format and credentials, and only then move on to specific settings for particular tools. Most problems can be resolved by correctly configuring the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables.