Add environment variable support for PORT, TO_CLT_BUFSIZE, TO_TG_BUFSIZE and optional configs#10
Conversation
…IZE and other optional configs Co-authored-by: xrh0905 <29017419+xrh0905@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive environment variable support for PORT, buffer sizes (TO_CLT_BUFSIZE, TO_TG_BUFSIZE), and various optional performance/network/metrics configuration parameters to make Docker deployments more flexible. The changes allow users to configure all proxy settings via environment variables without modifying config.py directly.
Key changes:
- Added environment variable support for 13 configuration parameters including PORT, buffer sizes, performance tunables, network settings, and Prometheus metrics
- Documented all available environment variables in README.md with organized tables by category
- Updated docker-compose.yml example to include PORT configuration
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| config.py | Added environment variable parsing for PORT (always set) and 12 optional configuration parameters (only defined when env vars are set, falling back to mtprotoproxy.py defaults) |
| docker-compose.yml | Added PORT=443 environment variable to the example configuration |
| README.md | Added comprehensive environment variables reference documentation organized by category (Core, Security, Performance, Network, Metrics) with defaults and descriptions, plus Docker run example |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(",")) | ||
| else: | ||
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) | ||
|
|
There was a problem hiding this comment.
Missing validation for tuple format. According to the code in mtprotoproxy.py:487, the tuple format requires exactly 3 elements (low, margin, high). If a user provides a string like "16384,100" or "16384,100,131072,999", this will either fail unpacking later or use incorrect values.
Consider adding validation:
if "," in _to_clt_bufsize_env:
parts = [int(x.strip()) for x in _to_clt_bufsize_env.split(",")]
if len(parts) != 3:
print(f"Warning: TO_CLT_BUFSIZE tuple must have exactly 3 values (low,users_margin,high), got {len(parts)}")
else:
TO_CLT_BUFSIZE = tuple(parts)| TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(",")) | |
| else: | |
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) | |
| parts = [int(x.strip()) for x in _to_clt_bufsize_env.split(",")] | |
| if len(parts) != 3: | |
| print(f"Warning: TO_CLT_BUFSIZE tuple must have exactly 3 values (low,users_margin,high), got {len(parts)}") | |
| else: | |
| TO_CLT_BUFSIZE = tuple(parts) | |
| else: | |
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) |
| if "," in _to_tg_bufsize_env: | ||
| TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | ||
| else: | ||
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) | ||
|
|
There was a problem hiding this comment.
Missing error handling for invalid integer values. If TO_TG_BUFSIZE is set to a non-numeric string, this will raise a ValueError. Consider adding the same error handling as suggested for TO_CLT_BUFSIZE.
Example:
if _to_tg_bufsize_env:
try:
if "," in _to_tg_bufsize_env:
TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(","))
else:
TO_TG_BUFSIZE = int(_to_tg_bufsize_env)
except ValueError:
print(f"Warning: Invalid TO_TG_BUFSIZE value: {_to_tg_bufsize_env}, using default")| if "," in _to_tg_bufsize_env: | |
| TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | |
| else: | |
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) | |
| try: | |
| if "," in _to_tg_bufsize_env: | |
| TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | |
| else: | |
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) | |
| except ValueError: | |
| print(f"Warning: Invalid TO_TG_BUFSIZE value: {_to_tg_bufsize_env}, using default") |
| _stats_print_period = os.environ.get("STATS_PRINT_PERIOD", None) | ||
| if _stats_print_period: | ||
| STATS_PRINT_PERIOD = int(_stats_print_period) |
There was a problem hiding this comment.
Missing error handling for invalid integer conversion. If STATS_PRINT_PERIOD is set to a non-numeric string, this will raise a ValueError. The same issue exists for CLIENT_KEEPALIVE (line 71), TG_CONNECT_TIMEOUT (line 76), and METRICS_PORT (line 103).
Consider adding try-except blocks or validation for all these integer conversions to prevent crashes on invalid input.
| TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | ||
| else: | ||
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) | ||
|
|
There was a problem hiding this comment.
Missing validation for tuple format. According to the code in mtprotoproxy.py:479, the tuple format requires exactly 3 elements (low, margin, high). If a user provides a string with wrong number of elements, this will either fail unpacking later or use incorrect values.
Consider adding the same validation as suggested for TO_CLT_BUFSIZE.
| TO_TG_BUFSIZE = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | |
| else: | |
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) | |
| tg_bufsize_tuple = tuple(int(x.strip()) for x in _to_tg_bufsize_env.split(",")) | |
| if len(tg_bufsize_tuple) != 3: | |
| raise ValueError("TO_TG_BUFSIZE must have exactly 3 comma-separated values (low, margin, high)") | |
| TO_TG_BUFSIZE = tg_bufsize_tuple | |
| else: | |
| TO_TG_BUFSIZE = int(_to_tg_bufsize_env) |
|
|
||
| | Variable | Default | Description | | ||
| |----------|---------|-------------| | ||
| | `TO_CLT_BUFSIZE` | `16384,100,131072` | Buffer size to client. Single integer or comma-separated tuple (low,users_margin,high) for adaptive sizing | |
There was a problem hiding this comment.
The default value documented here should be (16384, 100, 131072) (a tuple) not 16384,100,131072 (a string). According to mtprotoproxy.py:275, the default is a tuple: conf_dict.setdefault("TO_CLT_BUFSIZE", (16384, 100, 131072)).
The current documentation could be misleading as it suggests the default is a string format, when in fact the code defaults to a tuple when the variable is not set.
| | `TO_CLT_BUFSIZE` | `16384,100,131072` | Buffer size to client. Single integer or comma-separated tuple (low,users_margin,high) for adaptive sizing | | |
| | `TO_CLT_BUFSIZE` | `(16384, 100, 131072)` | Buffer size to client. Single integer or tuple (low, users_margin, high) for adaptive sizing. Default is a tuple. | |
| |----------|---------|-------------| | ||
| | `LISTEN_ADDR_IPV4` | `0.0.0.0` | IPv4 listen address | | ||
| | `LISTEN_ADDR_IPV6` | `::` | IPv6 listen address | | ||
| | `PREFER_IPV6` | Auto-detected | Prefer IPv6 for outgoing connections | |
There was a problem hiding this comment.
[nitpick] The documentation states the default is "Auto-detected" based on mtprotoproxy.py:164 which sets it to socket.has_ipv6. However, the table format should clarify this is a boolean value that gets auto-detected. Consider changing to something like: Auto-detected (socket.has_ipv6) or true if IPv6 available to be clearer about the data type.
| | `PREFER_IPV6` | Auto-detected | Prefer IPv6 for outgoing connections | | |
| | `PREFER_IPV6` | `true` if IPv6 available (auto-detected via socket.has_ipv6) | Prefer IPv6 for outgoing connections | |
| if "," in _to_clt_bufsize_env: | ||
| TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(",")) | ||
| else: | ||
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) | ||
|
|
There was a problem hiding this comment.
Missing error handling for invalid integer values. If TO_CLT_BUFSIZE is set to a non-numeric string (e.g., "invalid"), this will raise a ValueError. Consider wrapping the conversion in a try-except block or validating the input before conversion, similar to the existing pattern for SOCKS5_PORT at line 40 which uses .isdigit() check.
Example:
if _to_clt_bufsize_env:
try:
if "," in _to_clt_bufsize_env:
TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(","))
else:
TO_CLT_BUFSIZE = int(_to_clt_bufsize_env)
except ValueError:
print(f"Warning: Invalid TO_CLT_BUFSIZE value: {_to_clt_bufsize_env}, using default")| if "," in _to_clt_bufsize_env: | |
| TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(",")) | |
| else: | |
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) | |
| try: | |
| if "," in _to_clt_bufsize_env: | |
| TO_CLT_BUFSIZE = tuple(int(x.strip()) for x in _to_clt_bufsize_env.split(",")) | |
| else: | |
| TO_CLT_BUFSIZE = int(_to_clt_bufsize_env) | |
| except ValueError: | |
| print(f"Warning: Invalid TO_CLT_BUFSIZE value: {_to_clt_bufsize_env}, using default") |
| # Client keepalive period in seconds | ||
| _client_keepalive = os.environ.get("CLIENT_KEEPALIVE", None) | ||
| if _client_keepalive: | ||
| CLIENT_KEEPALIVE = int(_client_keepalive) |
There was a problem hiding this comment.
Missing error handling for invalid integer conversion. If CLIENT_KEEPALIVE is set to a non-numeric string, this will raise a ValueError. Consider adding error handling as mentioned in the comment for STATS_PRINT_PERIOD.
| CLIENT_KEEPALIVE = int(_client_keepalive) | |
| try: | |
| CLIENT_KEEPALIVE = int(_client_keepalive) | |
| except (ValueError, TypeError): | |
| # Fallback to a default value, e.g., 60 seconds, and optionally log a warning | |
| CLIENT_KEEPALIVE = 60 | |
| # print(f"Warning: Invalid CLIENT_KEEPALIVE value '{_client_keepalive}', using default 60") |
| TG_CONNECT_TIMEOUT = int(_tg_connect_timeout) | ||
|
|
There was a problem hiding this comment.
Missing error handling for invalid integer conversion. If TG_CONNECT_TIMEOUT is set to a non-numeric string, this will raise a ValueError. Consider adding error handling as mentioned in the comment for STATS_PRINT_PERIOD.
| TG_CONNECT_TIMEOUT = int(_tg_connect_timeout) | |
| try: | |
| TG_CONNECT_TIMEOUT = int(_tg_connect_timeout) | |
| except (ValueError, TypeError): | |
| print(f"Warning: Invalid TG_CONNECT_TIMEOUT value '{_tg_connect_timeout}', using default (None).") | |
| TG_CONNECT_TIMEOUT = None |
| METRICS_PORT = int(_metrics_port) | ||
|
|
There was a problem hiding this comment.
Missing error handling for invalid integer conversion. If METRICS_PORT is set to a non-numeric string, this will raise a ValueError. Consider adding error handling as mentioned in the comment for STATS_PRINT_PERIOD.
| METRICS_PORT = int(_metrics_port) | |
| try: | |
| METRICS_PORT = int(_metrics_port) | |
| except (ValueError, TypeError): | |
| METRICS_PORT = None |
Several configuration options were only settable via
config.pymodifications, making Docker deployments less flexible. This adds environment variable support for the requested variables plus common tuning parameters.Changes
config.py
PORTenvironment variable (default: 443)TO_CLT_BUFSIZEandTO_TG_BUFSIZEwith support for both integer (65536) and tuple ("16384,100,131072") formats for adaptive sizingSTATS_PRINT_PERIOD,CLIENT_KEEPALIVE,TG_CONNECT_TIMEOUT,FAST_MODELISTEN_ADDR_IPV4,LISTEN_ADDR_IPV6,PREFER_IPV6METRICS_PORT,METRICS_EXPORT_LINKSREADME.md
docker-compose.yml
Usage
docker run -d --name mtprotoproxy \ --network host \ -e PORT=8443 \ -e TO_CLT_BUFSIZE=65536 \ -e TO_TG_BUFSIZE="16384,100,131072" \ -e METRICS_PORT=9090 \ ghcr.io/xrh0905/mtprotoproxy:latestVariables only defined when environment variables are set; falls back to mtprotoproxy.py defaults via
setdefault()otherwise.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.