Skip to content

Instantly share code, notes, and snippets.

@arisnew
Created November 27, 2025 12:06
Show Gist options
  • Select an option

  • Save arisnew/09daf692c42b95de18fd3281fbb7a32e to your computer and use it in GitHub Desktop.

Select an option

Save arisnew/09daf692c42b95de18fd3281fbb7a32e to your computer and use it in GitHub Desktop.
API Proxy untuk meneruskan request dari docker ke external server jika dari docker terkendala VPN (Mac)

Biasanya aplikasi kita yang di dalam docker (Mac) tidak bisa hit ke API server eksternal yang koneksinya menggunakan VPN (dari host/laptop kita bisa, namun dari dalam docker tidak bisa).

Selain ubah konfigurasi network (yg mungkin masih gagal), solusi alternatifnya kita bisa lewatkan semacam API Proxy.

Berikut sample-nya:

# api_proxy.py
import http.server
import socketserver
import urllib.request
from urllib.error import URLError, HTTPError
import sys

UPSTREAM_IP = "172.20.88.213"
UPSTREAM_BASE = f"http://{UPSTREAM_IP}/JPayroll/thirdparty/ext"

class ProxyHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.proxy_request("GET")

    def do_POST(self):
        self.proxy_request("POST")

    def do_PUT(self):
        self.proxy_request("PUT")

    def do_DELETE(self):
        self.proxy_request("DELETE")

    def do_PATCH(self):
        self.proxy_request("PATCH")

    def do_HEAD(self):
        self.proxy_request("HEAD")

    def proxy_request(self, method):
        # Build full upstream URL
        upstream_url = UPSTREAM_BASE + self.path  # preserves query string

        # Read body (for POST/PUT)
        content_length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(content_length) if content_length > 0 else None

        # Prepare request
        req = urllib.request.Request(upstream_url, data=body, method=method)

        # logging
        print(f"➡️  {method} {upstream_url}", file=sys.stderr)
        print(f"   Headers: {dict(self.headers)}", file=sys.stderr)
        if body:
            print(f"   Body: {body.decode()}", file=sys.stderr)

        # 1 option: Forward all headers (opsional: filter jika perlu)
        # for key, value in self.headers.items():
        #     if key.lower() not in ('host', 'connection', 'content-length'):
        #         req.add_header(key, value)

        # 2 option: Forward all headers, TAPI override 'Host'
        for key, value in self.headers.items():
            key_lower = key.lower()
            if key_lower in ('connection', 'content-length'):
                continue
            elif key_lower == 'host':
                # Ganti dengan host upstream yang benar
                req.add_header('Host', UPSTREAM_IP)
            else:
                req.add_header(key, value)

        try:
            with urllib.request.urlopen(req, timeout=30) as response:
                self.send_response(response.status)
                for key, value in response.headers.items():
                    self.send_header(key, value)
                self.end_headers()
                self.wfile.write(response.read())
        except HTTPError as e:
            # Handle upstream HTTP errors (4xx, 5xx)
            self.send_response(e.code)
            for key, value in e.headers.items():
                self.send_header(key, value)
            self.end_headers()
            self.wfile.write(e.read())
        except URLError as e:
            self.send_response(502)  # Bad Gateway
            self.send_header("Content-Type", "text/plain")
            self.end_headers()
            self.wfile.write(f"Proxy Error: {e.reason}".encode())
        except Exception as e:
            self.send_response(500)
            self.send_header("Content-Type", "text/plain")
            self.end_headers()
            self.wfile.write(f"Internal Proxy Error: {str(e)}".encode())

# Jalankan di port 8081
if __name__ == "__main__":
    PORT = 8081
    with socketserver.TCPServer(("", PORT), ProxyHandler) as httpd:
        print(f"✅ Proxy siap di http://localhost:{PORT}")
        print(f"  → Semua request ke /... akan diteruskan ke {UPSTREAM_BASE}/...")
        print("  🛑 Tekan Ctrl+C untuk berhenti")
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\n🛑 Proxy dihentikan.")
            

Nanti semua request dari docker akan dilewatkan dan diteruskan oleh proxy ini.

awesomeApp (Docker) <-> API Proxy (host) <-(VPN)-> External API (external server / internet)

Seharusnya lebih simple dari pada obrak-abrik konfigurasi network docker / dns / vpn dan lain sebagainya.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment