Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Configure Proxy Settings Securely on Linux Servers

Why proxy settings become a security problem over time

In the beginning, a Linux server is usually simple: it pulls packages, reaches a few internal APIs, and maybe ships logs to a central system. Then the environment grows. Security teams introduce outbound controls. Compliance asks for audit trails. A proxy is added “temporarily” to enforce policy, and suddenly it becomes permanent infrastructure.

That is where things get interesting. A proxy is not just a networking detail; it becomes part of the trust chain. If SSL inspection is in play, the proxy is effectively participating in TLS. If we configure proxy settings casually, we can break package management, silently weaken certificate validation, or create inconsistent behavior across services. In enterprise environments, inconsistency is where outages and security gaps hide.

We are going to configure proxy settings on Linux servers in a way that is secure, persistent across reboots, predictable for automation, and explicitly aware of SSL inspection.

Prerequisites and assumptions

Before we touch configuration, we need to be explicit about the baseline. Proxy configuration is one of those areas where “it worked on one server” is not good enough.

  • Platform: Linux. The steps below are written for systemd-based distributions (common in enterprise fleets), including Debian/Ubuntu and RHEL/Rocky/Alma/CentOS Stream families.
  • OS state: A server with standard vendor package tooling (APT or DNF/YUM) and systemd. We assume no custom proxy tooling is already enforcing settings (for example, a configuration management agent may already manage environment files).
  • Access: We need shell access with sudo privileges. We will write to /etc and reload services.
  • Network: We need the proxy hostname and port for HTTP and HTTPS egress. In many enterprises, these are the same endpoint, but we will treat them explicitly.
  • SSL inspection aware: If the enterprise proxy performs TLS interception, we must install the organization’s inspection CA certificate into the OS trust store. Without this, TLS connections will fail with certificate errors, or worse, teams will be tempted to disable verification.
  • Security posture: We will not disable TLS verification. We will not weaken package manager security. We will keep secrets out of world-readable files.

We will also keep changes auditable: every file we create will have a clear purpose, and we will verify behavior after each major step.

Step 1: Capture proxy details safely and consistently

Before we write any configuration, we need a consistent way to represent the proxy endpoints. We will store them in shell variables for this session so commands remain copy/paste-safe. If credentials are required, we will avoid embedding them in global files and instead discuss safer patterns.

Identify current proxy-related environment and baseline connectivity

We are going to check whether proxy variables are already set and confirm basic DNS and routing. This prevents us from “fixing” the wrong problem.

env | grep -iE '^(http|https|no)_proxy=' || true
ip route show
getent hosts example.com | head -n 1

This shows whether the shell already has proxy variables, what the default route is, and whether DNS resolution works. If DNS is broken, proxy configuration will not help and we should fix name resolution first.

Set proxy variables for this session

We are going to define proxy endpoints as variables. This keeps the next commands consistent and reduces copy/paste mistakes. We will use a conservative default of HTTP CONNECT over the HTTPS proxy URL format, which is widely supported by enterprise tooling.

First, we will prompt ourselves to enter the proxy host and port in a controlled way. This avoids hardcoding unknown values into commands.

read -r -p "Proxy hostname (e.g., proxy.corp.example): " PROXY_HOST
read -r -p "Proxy port (e.g., 3128): " PROXY_PORT
export HTTP_PROXY="http://${PROXY_HOST}:${PROXY_PORT}"
export HTTPS_PROXY="http://${PROXY_HOST}:${PROXY_PORT}"
export http_proxy="${HTTP_PROXY}"
export https_proxy="${HTTPS_PROXY}"

We now have session-scoped proxy variables set for both uppercase and lowercase forms, which covers most Linux tooling. Nothing has been persisted yet; this is only for validation and for the next steps.

Verify proxy reachability without changing the system

We are going to confirm that the proxy endpoint is reachable on the network. This is a simple TCP check; it does not validate authentication or policy, but it confirms routing and firewall basics.

timeout 5 bash -c 'cat < /dev/null > /dev/tcp/'"${PROXY_HOST}"'/'"${PROXY_PORT}"'' && echo "Proxy TCP port reachable" || echo "Proxy TCP port NOT reachable"

If we see “NOT reachable,” the issue is upstream: routing, security groups, ACLs, or local firewall rules. We should resolve that before proceeding, because configuration changes will not overcome a blocked path.

Step 2: Make SSL inspection explicit by installing the enterprise CA

If SSL inspection is enabled, the proxy will present certificates signed by an enterprise CA. Our servers must trust that CA, or TLS will fail with errors like “unable to get local issuer certificate.” The secure approach is to install the CA into the OS trust store so standard verification continues to work.

We will first detect the OS family so we can use the correct trust store mechanism.

. /etc/os-release
echo "Detected: ${ID} ${VERSION_ID}"

This prints the distribution ID and version. Now we will proceed with the appropriate trust store steps.

Debian/Ubuntu family: install CA into system trust

We are going to place the enterprise inspection CA certificate in the location that update-ca-certificates reads, then rebuild the trust store. The certificate must be in PEM format (commonly .crt).

First, we will create a dedicated directory and set safe permissions. Then we will copy the CA file into place. We will not assume a filename; we will ask for the path to the CA file.

read -r -p "Path to enterprise inspection CA PEM file (e.g., /tmp/corp-inspection-ca.crt): " CA_PEM
sudo install -d -m 0755 /usr/local/share/ca-certificates/niilaa
sudo install -m 0644 "${CA_PEM}" /usr/local/share/ca-certificates/niilaa/corp-inspection-ca.crt
sudo update-ca-certificates

This installs the CA certificate with root ownership and world-readable permissions (appropriate for public CA material) and updates the system CA bundle. The trust store is now aware of the inspection CA.

We will verify that the CA is present in the generated bundle.

grep -n "BEGIN CERTIFICATE" -n /etc/ssl/certs/ca-certificates.crt | head -n 3
ls -l /etc/ssl/certs | grep -i "corp-inspection-ca" || true

The first command confirms the bundle exists and is populated; the second attempts to locate the symlinked certificate entry. On some systems, the symlink name may differ, so absence there is not automatically a failure if update-ca-certificates completed successfully.

RHEL/Rocky/Alma family: install CA into system trust

We are going to place the enterprise inspection CA certificate where update-ca-trust expects it, then rebuild the trust store.

read -r -p "Path to enterprise inspection CA PEM file (e.g., /tmp/corp-inspection-ca.crt): " CA_PEM
sudo install -d -m 0755 /etc/pki/ca-trust/source/anchors
sudo install -m 0644 "${CA_PEM}" /etc/pki/ca-trust/source/anchors/corp-inspection-ca.crt
sudo update-ca-trust extract

This anchors the CA into the system trust and regenerates the extracted trust bundles used by OpenSSL and other consumers.

We will verify that the trust store was updated.

ls -l /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
grep -n "BEGIN CERTIFICATE" -n /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem | head -n 3

If the bundle exists and contains certificates, the trust store is in place. The next step is to validate TLS behavior through the proxy.

Verify TLS through the proxy with certificate validation intact

We are going to perform an HTTPS request through the proxy and confirm that certificate validation succeeds. This is the moment where SSL inspection either works cleanly (trusted CA installed) or fails loudly (CA missing or wrong).

curl -fsSI --proxy "${HTTPS_PROXY}" https://example.com | head -n 5

If this returns HTTP headers without TLS errors, the trust chain is working. If it fails with certificate errors, we should not proceed to system-wide proxy persistence until the CA trust is corrected.

Step 3: Persist proxy settings for interactive shells and system services

In enterprise environments, the biggest source of proxy incidents is inconsistency: shells use one proxy, systemd services use none, and package managers do something else entirely. We will make proxy settings persistent in a controlled way.

We will implement two layers:

  • System-wide environment defaults for interactive shells and many tools.
  • systemd manager defaults so services started by systemd inherit proxy variables consistently.

Persist proxy variables in /etc/environment

We are going to write proxy variables into /etc/environment. This file is read by PAM on login and is a common enterprise baseline. We will also keep the file clean and avoid duplicating entries by managing a dedicated drop-in file instead of editing arbitrary existing lines.

Because /etc/environment does not support shell expansion, we will write literal values. We will also avoid embedding credentials here. If the proxy requires authentication, we should use a dedicated mechanism (discussed later) rather than placing secrets in a global environment file.

First, we will create a dedicated file under /etc/profile.d for shell sessions, and we will also update /etc/environment for broader compatibility.

sudo tee /etc/profile.d/proxy.sh > /dev/null <<'EOF'
# Managed proxy environment for interactive shells
export HTTP_PROXY="__HTTP_PROXY__"
export HTTPS_PROXY="__HTTPS_PROXY__"
export http_proxy="__HTTP_PROXY__"
export https_proxy="__HTTPS_PROXY__"
EOF

This creates a managed shell profile script. Right now it contains placeholders, so we will replace them safely using variables we already set in this session.

sudo sed -i "s|__HTTP_PROXY__|${HTTP_PROXY}|g; s|__HTTPS_PROXY__|${HTTPS_PROXY}|g" /etc/profile.d/proxy.sh
sudo chmod 0644 /etc/profile.d/proxy.sh

The profile script now exports the proxy variables for interactive shells. Permissions are set to be readable by all users, which is appropriate as long as we did not embed credentials.

Now we will update /etc/environment in a controlled way by appending managed lines only if they do not already exist.

sudo grep -q '^HTTP_PROXY=' /etc/environment || echo "HTTP_PROXY=${HTTP_PROXY}" | sudo tee -a /etc/environment > /dev/null
sudo grep -q '^HTTPS_PROXY=' /etc/environment || echo "HTTPS_PROXY=${HTTPS_PROXY}" | sudo tee -a /etc/environment > /dev/null
sudo grep -q '^http_proxy=' /etc/environment || echo "http_proxy=${HTTP_PROXY}" | sudo tee -a /etc/environment > /dev/null
sudo grep -q '^https_proxy=' /etc/environment || echo "https_proxy=${HTTPS_PROXY}" | sudo tee -a /etc/environment > /dev/null

This ensures the variables exist in /etc/environment without repeatedly duplicating them. Existing values are not overwritten; in managed fleets, overwriting should be done via configuration management with explicit intent.

We will verify what we wrote.

grep -iE '^(http|https)_proxy=' /etc/environment
sed -n '1,120p' /etc/profile.d/proxy.sh

We now have persistent proxy variables for logins and interactive shells.

Persist proxy variables for systemd services

Interactive shells are only half the story. Many enterprise workloads run as systemd services, and they may not read /etc/profile.d or /etc/environment the way we expect. The clean approach is to configure systemd’s manager environment so services inherit proxy variables consistently.

We are going to create a systemd drop-in for the manager configuration. This is safer than editing vendor files and survives updates.

sudo install -d -m 0755 /etc/systemd/system.conf.d
sudo tee /etc/systemd/system.conf.d/10-proxy.conf > /dev/null <<EOF
[Manager]
DefaultEnvironment="HTTP_PROXY=${HTTP_PROXY}" "HTTPS_PROXY=${HTTPS_PROXY}" "http_proxy=${HTTP_PROXY}" "https_proxy=${HTTPS_PROXY}"
EOF

This sets default environment variables for systemd-managed services. It does not restart services yet; it changes what systemd will apply going forward.

Now we will reload systemd manager configuration and verify the setting is visible.

sudo systemctl daemon-reexec
systemctl show --property=DefaultEnvironment

daemon-reexec restarts the systemd manager process in-place, applying the new configuration. The systemctl show output should include the proxy variables we set.

Step 4: Configure package managers explicitly (APT and DNF/YUM)

Even with environment variables, package managers deserve explicit configuration. They run as root, they are often invoked non-interactively, and they are the first place teams notice proxy issues. We will configure them in a way that is predictable and compatible with SSL inspection.

APT (Debian/Ubuntu): set proxy configuration

We are going to create an APT configuration file that defines HTTP and HTTPS proxy usage. This keeps package operations consistent regardless of shell environment.

if command -v apt-get >/dev/null 2>&1; then
  sudo tee /etc/apt/apt.conf.d/90-proxy > /dev/null <<EOF
Acquire::http::Proxy "${HTTP_PROXY}";
Acquire::https::Proxy "${HTTPS_PROXY}";
EOF
fi

This creates /etc/apt/apt.conf.d/90-proxy when APT is present. APT will now use the proxy for repository access.

We will verify APT sees the configuration and can reach repositories.

if command -v apt-get >/dev/null 2>&1; then
  sudo apt-get update
fi

If apt-get update succeeds without TLS errors, APT is correctly using the proxy and the trust store is compatible with SSL inspection.

DNF/YUM (RHEL family): set proxy configuration

We are going to configure DNF (or YUM on older systems) to use the proxy. This is done in the main configuration file so it applies consistently.

First, we will detect whether DNF or YUM is present.

PKG_MGR=""
command -v dnf >/dev/null 2>&1 && PKG_MGR="dnf"
command -v yum >/dev/null 2>&1 && [ -z "$PKG_MGR" ] && PKG_MGR="yum"
echo "Package manager: ${PKG_MGR:-none}"

Now we will apply the proxy setting if we detected a compatible manager. We will add the proxy line only if it does not already exist.

if [ "${PKG_MGR}" = "dnf" ] || [ "${PKG_MGR}" = "yum" ]; then
  CONF_FILE="/etc/dnf/dnf.conf"
  [ "${PKG_MGR}" = "yum" ] && CONF_FILE="/etc/yum.conf"

  sudo grep -q '^proxy=' "${CONF_FILE}" || echo "proxy=${HTTP_PROXY}" | sudo tee -a "${CONF_FILE}" > /dev/null
  sudo sed -n '1,120p' "${CONF_FILE}"
fi

This ensures the proxy is defined in the package manager configuration. We used the HTTP proxy URL because DNF/YUM uses it for both HTTP and HTTPS repository access via CONNECT where applicable.

We will verify repository metadata refresh works.

if [ "${PKG_MGR}" = "dnf" ]; then
  sudo dnf -y makecache
elif [ "${PKG_MGR}" = "yum" ]; then
  sudo yum -y makecache
fi

If cache generation succeeds without TLS errors, the package manager is correctly using the proxy and trusting the inspection CA.

Step 5: Handle credentials securely when the proxy requires authentication

Some enterprise proxies require authentication. The risky pattern is embedding username:password@ into global environment variables or world-readable files. That spreads secrets across logs, process lists, and configuration backups.

In production, we should prefer one of these approaches:

  • Network-based allowlisting for server subnets or service accounts at the proxy layer, so servers do not need embedded credentials.
  • Per-service systemd drop-ins with restricted permissions, using EnvironmentFile= readable only by root, and ideally populated by a secrets manager at deploy time.
  • Configuration management integration that templates credentials into root-only files and rotates them.

If we must use a root-only environment file for a specific service, we will do it in a way that does not expose secrets broadly. The pattern below shows the mechanics without forcing secrets into global scope.

Example: root-only EnvironmentFile for a single systemd service

We are going to create a root-only file that contains proxy variables, then attach it to a specific service via a systemd drop-in. This keeps credentials out of /etc/environment and out of user shells.

First, we create the environment file with strict permissions.

sudo install -d -m 0750 /etc/niilaa
sudo tee /etc/niilaa/proxy.env > /dev/null <<'EOF'
HTTP_PROXY=http://proxy.example:3128
HTTPS_PROXY=http://proxy.example:3128
http_proxy=http://proxy.example:3128
https_proxy=http://proxy.example:3128
EOF
sudo chown root:root /etc/niilaa/proxy.env
sudo chmod 0640 /etc/niilaa/proxy.env

This creates a controlled location for proxy settings. In a real environment, we would replace the example proxy values with the correct endpoint and, if required, credentials managed by an approved secrets process. The permissions ensure only root and the root group can read it.

Now we attach it to a service. We will demonstrate with cron as an example service name on many systems, but we will first detect a real unit name to avoid breaking anything.

SVC_CANDIDATES="cron crond"
SVC=""
for s in $SVC_CANDIDATES; do
  systemctl list-unit-files | awk '{print $1}' | grep -qx "${s}.service" && SVC="${s}.service" && break
done
echo "Selected service: ${SVC:-none}"

If a service was selected, we can apply the drop-in. If none was selected, we should choose the actual service we intend to configure and repeat the pattern.

if [ -n "$SVC" ]; then
  sudo systemctl edit "$SVC" --full --force <<'EOF'
[Service]
EnvironmentFile=/etc/niilaa/proxy.env
EOF
  sudo systemctl daemon-reload
  sudo systemctl restart "$SVC"
  sudo systemctl status "$SVC" --no-pager -l
fi

This binds proxy variables to a single service, reloads systemd, restarts the service, and shows status. The change is scoped and auditable.

Step 6: Firewall and egress considerations

Proxy configuration often fails for reasons that look like “proxy misconfiguration” but are actually egress controls. In enterprise networks, outbound traffic may be restricted to only the proxy. We should confirm the server can reach the proxy and that local firewall policy is not blocking it.

Check local firewall status

We are going to check common firewall tooling. This does not change anything; it only tells us what is enforcing policy locally.

sudo systemctl is-active ufw 2>/dev/null && sudo ufw status verbose || true
sudo systemctl is-active firewalld 2>/dev/null && sudo firewall-cmd --state && sudo firewall-cmd --list-all || true
sudo iptables -S 2>/dev/null | head -n 30 || true
sudo nft list ruleset 2>/dev/null | head -n 60 || true

This shows whether UFW or firewalld is active and prints a snapshot of rules. If outbound traffic to the proxy port is blocked, we will need to adjust policy according to enterprise standards.

Confirm active connections to the proxy during a request

We are going to generate a request through the proxy and observe the connection. This is a practical way to confirm traffic is actually going where we think it is going.

curl -fsS --proxy "${HTTP_PROXY}" http://example.com >/dev/null &
sleep 1
ss -tnp | grep -E ":${PROXY_PORT}b" || true

If we see an established TCP connection to the proxy port, the server is reaching the proxy. If not, we should revisit routing, firewall, or proxy hostname resolution.

Step 7: Verification checklist for production readiness

Now we will verify the configuration from multiple angles. In production, we want confidence that the behavior is consistent across reboots, across shells, and across services.

Verify environment persistence for logins

We are going to confirm that the proxy variables are present in a fresh login shell context.

bash -lc 'env | grep -iE "^(http|https)_proxy=" | sort'

This starts a login shell and prints proxy variables. If they appear, /etc/profile.d/proxy.sh is working.

Verify systemd default environment

We are going to confirm systemd manager defaults still include our proxy variables.

systemctl show --property=DefaultEnvironment

If the proxy variables are listed, system services started by systemd will inherit them unless overridden.

Verify package manager behavior

We are going to run a safe metadata operation again to confirm package tooling remains functional.

if command -v apt-get >/dev/null 2>&1; then
  sudo apt-get update
fi
if command -v dnf >/dev/null 2>&1; then
  sudo dnf -y makecache
fi
if command -v yum >/dev/null 2>&1; then
  sudo yum -y makecache
fi

Successful completion indicates that proxy configuration and CA trust are aligned with SSL inspection requirements.

Troubleshooting

When proxy configuration fails in enterprise environments, the symptoms are often consistent. The fastest path to resolution is matching the symptom to the layer: DNS, routing, proxy policy, TLS trust, or application-specific proxy handling.

Symptom: TLS errors like “unable to get local issuer certificate” or “certificate verify failed”

  • Likely cause: SSL inspection is active but the enterprise inspection CA is not installed (or the wrong CA was installed).
  • Fix: Reinstall the correct CA into the OS trust store and re-run the TLS verification through the proxy.

We will re-check with a strict curl call through the proxy:

curl -fsSI --proxy "${HTTPS_PROXY}" https://example.com | head -n 5

If this fails, we should confirm the CA file is correct and that the trust store update command completed successfully.

Symptom: “Could not resolve host” when using the proxy

  • Likely cause: DNS resolution is failing on the server, or the proxy hostname is not resolvable from this network segment.
  • Fix: Validate resolver configuration and confirm the proxy hostname resolves.
getent hosts "${PROXY_HOST}" || true
resolvectl status 2>/dev/null | sed -n '1,160p' || true
cat /etc/resolv.conf

If the proxy hostname does not resolve, we should fix DNS or use the correct internal DNS zone for the proxy endpoint.

Symptom: “Connection timed out” or “No route to host” to the proxy

  • Likely cause: Routing or firewall policy blocks access to the proxy port.
  • Fix: Confirm the default route, confirm the proxy port is reachable, and review local firewall state.
ip route show
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/'"${PROXY_HOST}"'/'"${PROXY_PORT}"'' && echo "Proxy reachable" || echo "Proxy NOT reachable"

If the proxy is not reachable, we should work with network/security teams to allow egress to the proxy from the server subnet.

Symptom: APT works, but a systemd service cannot reach outbound URLs

  • Likely cause: The service does not inherit the proxy environment, or it overrides environment variables.
  • Fix: Confirm systemd DefaultEnvironment is set, then inspect the service unit environment.
systemctl show --property=DefaultEnvironment
read -r -p "Service name to inspect (e.g., myapp.service): " SVC_NAME
systemctl show "$SVC_NAME" --property=Environment --property=EnvironmentFiles --no-pager

If the service has its own environment settings, we should add a service-specific drop-in with Environment= or EnvironmentFile= as appropriate, then restart the service.

Symptom: curl works in a shell, but package manager fails

  • Likely cause: Package manager is not using shell environment variables and needs explicit configuration, or it is using a different trust store path.
  • Fix: Confirm APT/DNF/YUM proxy config files exist and re-run cache/update operations.
if command -v apt-get >/dev/null 2>&1; then
  ls -l /etc/apt/apt.conf.d/90-proxy
  cat /etc/apt/apt.conf.d/90-proxy
fi
if command -v dnf >/dev/null 2>&1; then
  grep -n '^proxy=' /etc/dnf/dnf.conf || true
fi
if command -v yum >/dev/null 2>&1; then
  grep -n '^proxy=' /etc/yum.conf || true
fi

If configuration is present but failures persist, we should review proxy policy (some proxies restrict repository domains) and confirm the inspection CA is correct.

Common mistakes

  • Mistake: Installing the wrong CA certificate for SSL inspection.

    Symptom: curl through the proxy fails with certificate verification errors, while direct internal TLS may still work.

    Fix: Obtain the correct enterprise inspection CA chain from the security team, install it into the OS trust store, and re-run the proxy TLS verification command.

  • Mistake: Setting proxy variables only in a user’s shell profile.

    Symptom: Interactive commands work, but systemd services and scheduled jobs fail outbound connectivity.

    Fix: Configure systemd DefaultEnvironment and/or service-specific drop-ins, then restart affected services.

  • Mistake: Embedding proxy credentials in world-readable files.

    Symptom: Credentials appear in configuration backups, are readable by non-privileged users, or leak into logs.

    Fix: Use root-only EnvironmentFile for specific services, or implement proxy-side authentication methods that do not require distributing secrets to servers.

  • Mistake: Assuming package managers will honor environment variables.

    Symptom: curl works, but apt-get update or dnf makecache fails.

    Fix: Add explicit APT/DNF/YUM proxy configuration and re-run update/makecache to confirm.

  • Mistake: Not validating reachability to the proxy port.

    Symptom: Timeouts and intermittent failures that look like “proxy issues” but are actually routing or firewall blocks.

    Fix: Confirm TCP reachability to the proxy endpoint and review local firewall state before changing application configs.

How do we at NIILAA look at this

This setup is not impressive because it is complex. It is impressive because it is controlled. Every component is intentional. Every configuration has a reason. This is how infrastructure should scale — quietly, predictably, and without drama.

At NIILAA, we help enterprises design and standardize proxy-aware Linux baselines, integrate SSL inspection trust correctly, align systemd and package manager behavior, and keep the result maintainable under automation and audit. We also help teams validate egress policy, harden configurations, and operationalize troubleshooting so proxy changes stop being a recurring incident category.

Leave A Comment

All fields marked with an asterisk (*) are required