Setup a Static IP for Python & MongoDB using SOCKS

Learn how to route Python PyMongo traffic through a QuotaGuard Static IP using a native SOCKS proxy.

Prerequisites

pip install pymongo PySocks

Environment Variables

QUOTAGUARDSTATIC_URL: Your QuotaGuard Static proxy URL:

‍socks5://user:password@eu-west-static-01.quotaguard.com:1080

Found in your QuotaGuard Dashboard.

MONGO_URIA standard mongodb:// connection string with explicit hosts (see below).

Note: mongodb+srv:// URIs are not supported — DNS SRV lookups happen before the proxy is involved. See below for how to convert.

Getting a mongodb:// URI from your mongodb+srv:// URI

Run this once from any machine that can reach MongoDB directly:

from pymongo import MongoClient

client = MongoClient("mongodb+srv://user:password@your-cluster.mongodb.net/",
                     serverSelectionTimeoutMS=10000)
info = client.admin.command("isMaster")
print("Replica Set:", info.get("setName"))
print("Hosts:", info.get("hosts"))

Then build your URI:

mongodb://user:password@host1:27017,host2:27017,host3:27017/?ssl=true&replicaSet=<setName>&authSource=admin

Instructions

Connect to MongoDB through a QuotaGuard Static SOCKS5 proxy using pure Python, no QGTunnel wrapper required.

Suitable for environments where you can't run a wrapper process, such as PythonAnywhere.

Using this in your own project

1. Copy quotaguard.py into your project.

2. At the very top of your entry point — before importing pymongo or any other network library — add:

from quotaguard import configure_socks_proxy
configure_socks_proxy()

3. Then import and use pymongo as normal:

from pymongo import MongoClient

client = MongoClient(os.environ["MONGO_URI"])

That's it. Every TCP connection your process makes will be routed through the proxy.

Running the example app
# Directly
QUOTAGUARDSTATIC_URL=socks5://... MONGO_URI=mongodb://... python app.py

# Docker
docker build -t qg-static-python-mongo-example .
docker run \
  -e QUOTAGUARDSTATIC_URL=socks5://... \
  -e MONGO_URI=mongodb://... \
  qg-static-python-mongo-example

Code Samples

app.py
"""
MongoDB (PyMongo) via QuotaGuard Static — no QGTunnel.

Copy quotaguard.py into your project, then follow the same three-step pattern
shown here: call configure_socks_proxy(), import MongoClient, write your app.

Environment variables:
    QUOTAGUARDSTATIC_URL  socks5://user:password@...quotaguard.com:1080
    MONGO_URI             mongodb://user:password@host1:27017,.../?ssl=true&...

Note: mongodb+srv:// URIs are not supported — see the README for how to convert.
"""

import os

# ── Step 1: patch the socket layer BEFORE importing pymongo ─────────────────────
from quotaguard import configure_socks_proxy
configure_socks_proxy()

# ── Step 2: now it's safe to import pymongo ─────────────────────────────────────
from pymongo import MongoClient


# ── Step 3: write your application as normal ────────────────────────────────────
def main():
    mongo_uri = os.environ.get("MONGO_URI")
    if not mongo_uri:
        raise RuntimeError("Set MONGO_URI to a standard mongodb:// connection string.")

    if mongo_uri.startswith("mongodb+srv://"):
        raise RuntimeError(
            "mongodb+srv:// URIs are not supported — DNS SRV lookups bypass the proxy.\n"
            "Please convert to a standard mongodb:// URI first (see the README)."
        )

    print("Connecting to MongoDB via QuotaGuard Static...")
    client = MongoClient(mongo_uri, serverSelectionTimeoutMS=10000)

    result = client.admin.command("ping")
    print(f"MongoDB ping: {result}")
    print("✓ Successfully connected to MongoDB through QuotaGuard Static")


if __name__ == "__main__":
    main()

quotaguard.py
"""
quotaguard.py — drop this file into your project unchanged.

Call configure_socks_proxy() once at the very top of your entry point,
before importing pymongo or any other network library.
"""

import os
import socket as _socket
import socks
from urllib.parse import urlparse


def configure_socks_proxy():
    """
    Configure PySocks as the default SOCKS5 proxy and monkey-patch socket.socket
    so that all outgoing TCP connections are routed through QuotaGuard Static.

    Must be called before importing pymongo (or any other network library).
    """
    proxy_url = os.getenv("QUOTAGUARDSTATIC_URL") or os.getenv("QUOTAGUARD_URL")
    if not proxy_url:
        raise RuntimeError(
            "No proxy URL found. Set the QUOTAGUARDSTATIC_URL environment variable "
            "to your QuotaGuard Static proxy URL."
        )

    proxy = urlparse(proxy_url)
    if proxy.scheme not in ("socks5", "socks5h"):
        raise RuntimeError(
            f"Expected a socks5:// proxy URL, got scheme: {proxy.scheme!r}. "
            f"Check your QUOTAGUARDSTATIC_URL value."
        )
    if not proxy.hostname or not proxy.port:
        raise RuntimeError("Proxy URL is missing a host or port.")

    # Configure PySocks to use this proxy for all new sockets
    socks.set_default_proxy(
        socks.SOCKS5,
        proxy.hostname,
        int(proxy.port),
        rdns=True,           # Resolve hostnames on the proxy side
        username=proxy.username,
        password=proxy.password,
    )

    # Replace socket.socket with socks.socksocket so all connections use the proxy
    _socket.socket = socks.socksocket

    # PyMongo creates sockets with SOCK_CLOEXEC OR'd into the type flag:
    #   socket.socket(af, socktype | getattr(socket, "SOCK_CLOEXEC", 0), proto)
    # This produces a type value of 524289 (SOCK_STREAM | SOCK_CLOEXEC), which
    # ssl.SSLSocket then rejects with "Socket type must be stream or datagram".
    # Removing SOCK_CLOEXEC from the socket module causes PyMongo to fall back to
    # creating plain SOCK_STREAM sockets, which ssl is happy with.
    if hasattr(_socket, "SOCK_CLOEXEC"):
        del _socket.SOCK_CLOEXEC

Docker File
# Use an official Python runtime as a parent image
FROM python:latest

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install the required Python packages
RUN pip install --no-cache-dir pymongo PySocks

# Command to run when the container starts, assuming the environment variable is passed at runtime
CMD ["python", "app.py"]