Skip to main content
Mostafa Effati

About this platform

A working notebook for engineering practice

This is Mostafa Effati’s personal engineering platform: a place to turn hands-on work into clear writing, structured learning, and useful digital products.

Student collaborator

  • Ms Zahra Ehsani

    Former student · platform contributor

    Ms Zahra Ehsani worked on parts of this platform during her studies and brought thoughtful, practical contributions to its development. I'm glad to recognize her work here.

What you will find

  • Long-form articles, books, tutorials, and practical snippets.
  • Courses and guided learning paths built around real engineering work.
  • Case studies, open-source work, experiments, and product releases.

Built deliberately

  • A bilingual Persian and English experience with native RTL support.
  • Theme-aware, keyboard-friendly interfaces with a focused visual language.
  • Content and product changes developed as one versioned system.

The platform is continuously evolving. Some sections are complete products; others are active experiments that improve as the underlying work develops.

Keeping Docker, Git, and CI/CD Alive During Internet Disruptions

Keeping Docker, Git, and CI/CD alive on Iranian servers during internet disruptions with SSH reverse tunneling and a local proxy.
Mostafa Effati4 min readdeveloper-experience

Keeping Docker, Git, and CI/CD Alive on Iranian Servers During Internet Disruptions with Reverse SSH Tunneling

(Using SSH Reverse Tunneling + Local Proxy)

When the internet becomes unreliable, the first things that break are usually the “invisible” parts of engineering work: package downloads, Docker pulls, CI/CD pipelines, and even basic access to internal servers.

Recently, I faced a situation where connectivity was so unstable that even reaching domestic servers was unreliable. I could sometimes SSH into the server, but the server itself couldn’t reliably access the public internet. That meant no Docker installation, no dependency downloads, and no normal deployment workflow.

This post documents a workaround that worked for me: tunneling internet access from my own machine to a server via SSH reverse port forwarding, by exposing a local HTTP/SOCKS proxy on the server’s localhost interface.

It’s a pragmatic solution for emergencies — not a perfect long-term network design.

The idea (high level)

Assumptions:

  • You have a machine (laptop/desktop) with some working internet access.
  • You can at least occasionally connect to your server via SSH (even if only through mobile internet).
  • On your local machine, you can run a proxy (HTTP and/or SOCKS5). This could be Clash, V2Ray, Squid, etc.

Goal:

  • Make the server able to send outbound traffic “through” your local proxy — so it can:
    • install packages (dnf / yum / apt)
    • pull images (docker pull)
    • access Git repos / registries (when needed)

Step 1: Run a local proxy (HTTP and/or SOCKS5)

On your local machine, make sure you have a proxy listening on your LAN (or localhost). In my case, the proxy was reachable at:

  • 192.168.1.102:2080

Your values may differ depending on your setup.

Step 2: Expose the local proxy on the server using SSH reverse port forwarding

From your local machine, run:

ssh -o ServerAliveInterval=20 -o ServerAliveCountMax=3 \
  -R 127.0.0.1:10809:192.168.1.102:2080 \
  -R 127.0.0.1:10808:192.168.1.102:2080 \
  root@X.X.X.X

What this does:

  • It binds two ports on the server (only on 127.0.0.1):
    • 127.0.0.1:10808
    • 127.0.0.1:10809
  • Any connection to those ports on the server is forwarded back to your local machine’s proxy endpoint (192.168.1.102:2080).

I used:

  • 10808 as an HTTP proxy endpoint
  • 10809 as a SOCKS5 proxy endpoint

(If your proxy software only supports one protocol, you only need one mapping.)

Security note: binding to 127.0.0.1 is important. It prevents exposing your proxy to the public internet.

Step 3: Test outbound connectivity from the server

For SOCKS5 via curl:

curl --socks5 127.0.0.1:10809 https://cloudflare.com

If you want to run a script through the proxy:

ALL_PROXY=socks5://127.0.0.1:10809 \
  curl -fsSL --socks5 127.0.0.1:10809 \
  https://example.com/script.sh | sh

Step 4: Configure Docker to use the proxy (systemd)

On RHEL-based systems (CentOS / AlmaLinux / Rocky), create:

sudo mkdir -p /etc/systemd/system/docker.service.d/
sudo nano /etc/systemd/system/docker.service.d/proxy.conf

Add:

[Service]
Environment="ALL_PROXY=socks5://127.0.0.1:10809"
Environment="HTTP_PROXY=http://127.0.0.1:10808"
Environment="HTTPS_PROXY=http://127.0.0.1:10808"

Then reload and restart Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

At this point, Docker pulls should start working (assuming the tunnel is up).

Step 5: Use the proxy with dnf / yum

Example with dnf:

sudo dnf --setopt=proxy=http://127.0.0.1:10808 install unzip

Example with yum:

sudo yum --setopt=proxy=http://127.0.0.1:10808 install unzip

Once you can stabilize basic server operations, it helps to reduce how often you need external services.

A few useful self-hosted tools:

  • Gitea — lightweight Git hosting (and a base for a more resilient workflow)
  • Verdaccio — private npm registry cache
  • Kellnr — Rust crates registry / proxy

Even partial self-hosting can dramatically improve survival during outages.

Final notes / caveats

  • This is a workaround, not a substitute for proper infrastructure.
  • Treat it as an emergency bridge for package installs, image pulls, and short-term recovery.
  • Keep the SSH tunnel session stable (ServerAliveInterval helps).
  • Avoid binding remote forwarded ports to 0.0.0.0 unless you fully understand the security implications.

Canonical version. Also on Medium.

Related documents

Command menu

↑ ↓to move · Enter to select · Esc to close
Navigation
Actions

Press Esc to close · ⌘K to toggle