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.