Azure
Provision on-demand HTTP(S) proxy servers on Azure Virtual Machines with a single Python call. Each proxy runs Squid on an Ubuntu 24.04 LTS VM and is fully managed — creation, authentication, firewall rules, and cleanup are handled automatically.
Table of Contents
Requirements
Dependency |
Purpose |
|---|---|
|
Azure authentication (DefaultAzureCredential) |
|
List available regions |
|
Manage resource groups |
|
NSG, VNet, public IP, NIC management |
|
Virtual machine lifecycle |
Installation
pip install auto_proxy_vpn[azure]
Azure Credentials Setup
You need an Azure subscription. Authentication is handled by the Azure SDK’s DefaultAzureCredential, which tries multiple credential sources automatically. Choose the option that best fits your workflow:
Option A: Azure CLI Login (simplest)
If you already have the Azure CLI installed, just log in and set your subscription ID:
az login
Then provide only the subscription ID. The recommended way is to create a .env file in your project root:
# .env
AZURE_SUBSCRIPTION_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Load it at the start of your script:
from dotenv import load_dotenv
load_dotenv() # reads .env into environment variables
manager = ProxyManagerAzure(ssh_key="ssh-rsa AAAAB3...")
Alternatively, pass the subscription ID directly in code:
manager = ProxyManagerAzure(
credentials="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", # subscription ID
ssh_key="ssh-rsa AAAAB3..."
)
Note: This option is ideal for local development and interactive use.
DefaultAzureCredentialwill pick up the session fromaz loginautomatically.
Option B: Service Principal (recommended for automation)
Create a Service Principal with Contributor role:
az ad sp create-for-rbac \
--name "auto-proxy-vpn" \
--role contributor \
--scopes /subscriptions/{your-subscription-id}
This outputs:
{
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"password": "your-client-secret",
"tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Map the output fields to the following variable names and store them in a .env file:
CLI output |
|
|---|---|
|
|
|
|
|
|
(your subscription id) |
|
# .env
AZURE_SUBSCRIPTION_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AZURE_CLIENT_SECRET=your-client-secret
AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Load the .env file at the start of your script:
from dotenv import load_dotenv
load_dotenv()
manager = ProxyManagerAzure(ssh_key="ssh-rsa AAAAB3...")
Alternatively, pass credentials directly in code (less secure — avoid committing secrets):
manager = ProxyManagerAzure(
credentials={
"AZURE_SUBSCRIPTION_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AZURE_CLIENT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AZURE_CLIENT_SECRET": "your-client-secret",
"AZURE_TENANT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
},
ssh_key="ssh-rsa AAAAB3..."
)
⚠️ Security: Never use
exportto set credentials in your shell history or commit secrets to version control. Always use a.envfile and add it to your.gitignore. Installpython-dotenvwithpip install python-dotenv.This option is best suited for CI/CD pipelines, servers, and unattended scripts.
Quick Start
Import
from auto_proxy_vpn.providers.azure import ProxyManagerAzure, AzureProxy
Using Environment Variables (recommended)
manager = ProxyManagerAzure(
ssh_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC2..."
)
# Context manager — proxy is destroyed automatically on exit
with manager.get_proxy() as proxy:
print(proxy.get_proxy_str()) # http://203.0.113.42:34521
print(proxy.get_proxy()) # {'http': '...', 'https': '...'}
import requests
r = requests.get("https://httpbin.org/ip", proxies=proxy.get_proxy())
print(r.json())
Passing Credentials Explicitly
manager = ProxyManagerAzure(
credentials={
"AZURE_SUBSCRIPTION_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AZURE_CLIENT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AZURE_CLIENT_SECRET": "your-client-secret",
"AZURE_TENANT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
},
ssh_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC2..."
)
Manual Lifecycle
proxy = manager.get_proxy()
try:
r = requests.get("https://httpbin.org/ip", proxies=proxy.get_proxy())
print(r.json())
finally:
proxy.close() # destroys Azure resources
API Reference
ProxyManagerAzure
Factory class that provisions and manages Azure proxy VMs.
VM sizes:
Size |
Azure SKU |
|---|---|
|
|
|
|
|
|
ProxyManagerAzure(
ssh_key, # str | dict | list — SSH public key(s) or path to key file
credentials="", # str | dict — subscription ID, credential dict, or "" for env vars
log=True, # bool — enable logging
log_file=None, # str | None — log file path (None = stdout)
log_format="...", # str — Python logging format string
logger=None, # Logger | None — custom logger instance
)
manager.get_proxy()
Create and start a new proxy VM.
proxy = manager.get_proxy(
port=0, # int — proxy port (0 = random 10000–65000)
size="medium", # "small" | "medium" | "large"
region="", # str — Azure region (empty = random)
auth={}, # {"user": ..., "password": ...} — basic auth
allowed_ips=[], # str | list[str] — allowed source IPs (your IP is auto-added)
is_async=False, # bool — return immediately without waiting for full startup
retry=True, # bool — retry in a different region on failure
proxy_name="", # str — explicit name (empty = auto-generated)
on_exit="destroy", # "destroy" | "keep" — cleanup behavior on close
)
manager.get_proxies()
Create multiple proxies in one call and return a ProxyBatch.
batch = manager.get_proxies(
number=3,
sizes=["small", "medium", "large"],
is_async=True,
)
for proxy in batch:
print(proxy.get_proxy_str())
batch.close()
manager.get_proxy_by_name()
Reload a previously created (and still running) proxy by name.
proxy = manager.get_proxy_by_name(
name="proxy1", # str — existing proxy resource group name
is_async=False, # bool
on_exit="destroy", # "destroy" | "keep"
)
manager.get_running_proxy_names()
List names of all running proxy resource groups.
names = manager.get_running_proxy_names()
# ["proxy1", "proxy2"]
AzureProxy
Represents a single proxy VM instance. You typically get this from manager.get_proxy() rather than constructing it directly.
Properties
Property |
Type |
Description |
|---|---|---|
|
|
Public IPv4 address |
|
|
Proxy TCP port |
|
|
Azure region |
|
|
Basic-auth username (empty if none) |
|
|
Basic-auth password (empty if none) |
|
|
Whether the proxy is confirmed reachable |
|
|
Resource group / VM name |
Methods
Method |
Returns |
Description |
|---|---|---|
|
|
Proxy URL, e.g. |
|
|
|
|
|
Check (or wait for) proxy readiness |
|
|
Stop proxy; destroys resources if |
Context Manager
with manager.get_proxy() as proxy:
# proxy is guaranteed active here
r = requests.get("https://example.com", proxies=proxy.get_proxy())
# proxy resources are automatically cleaned up
Advanced Usage
Proxy with Basic Authentication
proxy = manager.get_proxy(
auth={"user": "myuser", "password": "s3cret"},
)
# Proxy URL: http://myuser:s3cret@<ip>:<port>
Restrict Access by IP
proxy = manager.get_proxy(
allowed_ips=["203.0.113.10", "198.51.100.0/24"],
)
# Your current public IP is always added automatically
Keep Proxy Alive After Close
proxy = manager.get_proxy(on_exit="keep")
proxy.close() # resources are NOT deleted
# Later, reconnect to it:
proxy = manager.get_proxy_by_name("proxy1", on_exit="destroy")
Asynchronous Creation
proxy = manager.get_proxy(is_async=True)
# Do other work while the VM provisions...
# Block until ready when you need it:
if proxy.is_active(wait=True):
r = requests.get("https://example.com", proxies=proxy.get_proxy())
SSH Key from File
manager = ProxyManagerAzure(
ssh_key="/path/to/authorized_keys", # one public key per line
)