Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Docker Image CI

on:
push:
branches:
- edge
tags:
- 'v*.*.*'
pull_request:
branches:
- edge
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix={{branch}}-
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tagging strategy includes type=sha,prefix={{branch}}- which will attempt to use {{branch}} as a literal prefix. The docker/metadata-action doesn't support {{branch}} as a template variable in the prefix. This will result in tags like {{branch}}-abc1234 instead of edge-abc1234.

Consider using one of these approaches:

  • Remove the SHA tagging: delete line 51
  • Use a fixed prefix: type=sha,prefix=edge- (but this only works for the edge branch)
  • Use type=sha without a prefix for simpler SHA-based tags
Suggested change
type=sha,prefix={{branch}}-
type=sha,prefix=edge-

Copilot uses AI. Check for mistakes.
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/edge' }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The workflow doesn't include any security scanning or vulnerability checking for the built Docker images. Consider adding a security scanning step using tools like Trivy or Snyk to detect vulnerabilities before pushing images to the registry.

Example addition after the build step:

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
          format: 'sarif'
          output: 'trivy-results.sarif'
Suggested change
cache-to: type=gha,mode=max
cache-to: type=gha,mode=max
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
format: 'sarif'
output: 'trivy-results.sarif'

Copilot uses AI. Check for mistakes.
104 changes: 103 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
# Async MTProto Proxy #

[![Docker Image](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/xrh0905/mtprotoproxy/pkgs/container/mtprotoproxy)

Fast and simple to setup MTProto proxy written in Python.

## Starting Up ##

### Using Pre-built Docker Image (Recommended) ###

1. Pull the latest image: `docker pull ghcr.io/xrh0905/mtprotoproxy:latest`
2. *(optional, recommended)* create a *config.py* file, set **PORT**, **USERS** and **AD_TAG**
3. Run the container:
```bash
docker run -d --name mtprotoproxy \
--network host \
-v $(pwd)/config.py:/home/tgproxy/config.py \
ghcr.io/xrh0905/mtprotoproxy:latest
```
4. *(optional, get a link to share the proxy)* `docker logs mtprotoproxy`

### Building from Source ###

1. `git clone -b stable https://github.com/alexbers/mtprotoproxy.git; cd mtprotoproxy`
1. `git clone -b edge https://github.com/xrh0905/mtprotoproxy.git; cd mtprotoproxy`
2. *(optional, recommended)* edit *config.py*, set **PORT**, **USERS** and **AD_TAG**
3. `docker build -t mtprotoproxy .`
4. `docker-compose up -d` (or just `python3 mtprotoproxy.py` if you don't like Docker)
5. *(optional, get a link to share the proxy)* `docker-compose logs`

![Demo](https://alexbers.com/mtprotoproxy/install_demo_v2.gif)

## Using with Docker Compose ##

You can use the pre-built image with docker-compose by updating your `docker-compose.yml`:

```yaml
version: '3.8'
services:
mtprotoproxy:
image: ghcr.io/xrh0905/mtprotoproxy:latest
restart: unless-stopped
network_mode: "host"
environment:
# Replace these values with your own configuration
- TG_KEY=00000000000000000000000000000001
- SECURE_ONLY=true
- TLS_ONLY=true
- TLS_DOMAIN=www.drive.google.com
- AD_TAG=3c09c680b76ee91a4c25ad51f742267d
volumes:
- ./config.py:/home/tgproxy/config.py
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The volumes section is indented with 8 spaces instead of 4 spaces, which is inconsistent with the rest of the YAML structure and violates YAML best practices. All keys at the same level should have the same indentation.

Change:

    volumes:
        - ./config.py:/home/tgproxy/config.py

To:

    volumes:
      - ./config.py:/home/tgproxy/config.py
Suggested change
- ./config.py:/home/tgproxy/config.py
- ./config.py:/home/tgproxy/config.py

Copilot uses AI. Check for mistakes.
```

Then run: `docker-compose up -d`

## Channel Advertising ##

To advertise a channel get a tag from **@MTProxybot** and put it to *config.py*.
Expand All @@ -33,3 +74,64 @@ The proxy can be launched:
- several times, clients will be automaticaly balanced between instances
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "automaticaly" should be "automatically".

Suggested change
- several times, clients will be automaticaly balanced between instances
- several times, clients will be automatically balanced between instances

Copilot uses AI. Check for mistakes.
- with uvloop module to get an extra speed boost
- with runtime statistics exported to [Prometheus](https://prometheus.io/)

### Using SOCKS5 as Outgoing Proxy ###

You can configure the MTProto proxy to use a SOCKS5 proxy for outgoing connections to Telegram servers. This is useful when your server cannot directly connect to Telegram or you want to route traffic through another proxy.

**Note:** SOCKS5 mode is incompatible with middle proxy advertising and uvloop.

#### Configuration in config.py ####

Add the following settings to your `config.py`:

```python
# SOCKS5 proxy settings (optional)
SOCKS5_HOST = "your.socks5.server.com" # SOCKS5 proxy hostname or IP
SOCKS5_PORT = 1080 # SOCKS5 proxy port
SOCKS5_USER = "username" # Optional: SOCKS5 username (set to None if not needed)
SOCKS5_PASS = "password" # Optional: SOCKS5 password (set to None if not needed)
```

#### Using Environment Variables ####

You can also configure SOCKS5 using environment variables:

```bash
docker run -d --name mtprotoproxy \
--network host \
-e SOCKS5_HOST=your.socks5.server.com \
-e SOCKS5_PORT=1080 \
-e SOCKS5_USER=username \
-e SOCKS5_PASS=password \
-v $(pwd)/config.py:/home/tgproxy/config.py \
ghcr.io/xrh0905/mtprotoproxy:latest
```

#### Docker Compose Example with SOCKS5 ####

```yaml
version: '3.8'
services:
mtprotoproxy:
image: ghcr.io/xrh0905/mtprotoproxy:latest
restart: unless-stopped
network_mode: "host"
environment:
- TG_KEY=00000000000000000000000000000001
- SECURE_ONLY=true
- TLS_ONLY=true
- TLS_DOMAIN=www.drive.google.com
# SOCKS5 proxy configuration
- SOCKS5_HOST=your.socks5.server.com
- SOCKS5_PORT=1080
Comment on lines +125 to +127
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The documentation shows example credentials (TG_KEY, SOCKS5_USER, SOCKS5_PASS) but doesn't emphasize strongly enough that these are placeholder values that MUST be changed. While there is a comment on line 44 about replacing values, sensitive credentials like SOCKS5_USER and SOCKS5_PASS in the SOCKS5 example (lines 128-129) lack this warning.

Consider adding a similar comment in the SOCKS5 Docker Compose example to make it clear these are placeholder values:

    environment: 
      # Replace these values with your own configuration
      - TG_KEY=00000000000000000000000000000001
      - SECURE_ONLY=true
      - TLS_ONLY=true
      - TLS_DOMAIN=www.drive.google.com
      # SOCKS5 proxy configuration - replace with your actual SOCKS5 proxy details
      - SOCKS5_HOST=your.socks5.server.com
Suggested change
# SOCKS5 proxy configuration
- SOCKS5_HOST=your.socks5.server.com
- SOCKS5_PORT=1080
# SOCKS5 proxy configuration - replace with your actual SOCKS5 proxy details
- SOCKS5_HOST=your.socks5.server.com
- SOCKS5_PORT=1080
# Replace these placeholder credentials with your actual SOCKS5 username and password

Copilot uses AI. Check for mistakes.
- SOCKS5_USER=username
- SOCKS5_PASS=password
volumes:
- ./config.py:/home/tgproxy/config.py
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The volumes section is indented with 8 spaces instead of 4 spaces, which is inconsistent with the rest of the YAML structure and violates YAML best practices. All keys at the same level should have the same indentation.

Change:

    volumes:
        - ./config.py:/home/tgproxy/config.py

To:

    volumes:
      - ./config.py:/home/tgproxy/config.py
Suggested change
- ./config.py:/home/tgproxy/config.py
- ./config.py:/home/tgproxy/config.py

Copilot uses AI. Check for mistakes.
```

**Important:** When SOCKS5 is enabled:
- The middle proxy feature is automatically disabled
- uvloop acceleration is not available
- Channel advertising may not work
7 changes: 7 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ def str_to_bool(value):

# Tag for advertising, obtainable from @MTProxybot
AD_TAG = os.environ.get("AD_TAG", "3c09c680b76ee91a4c25ad51f742267d")

# SOCKS5 proxy for outgoing connections (optional)
# Uncomment and configure if you need to route traffic through a SOCKS5 proxy
SOCKS5_HOST = os.environ.get("SOCKS5_HOST", None)
SOCKS5_PORT = int(os.environ.get("SOCKS5_PORT", 0)) if os.environ.get("SOCKS5_PORT", "").isdigit() else None
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SOCKS5_PORT handling has a logical issue. If SOCKS5_PORT is set to "0" (a valid string that is all digits), isdigit() returns True and int(0) is 0, which is a falsy value. This means the condition if config.SOCKS5_HOST and config.SOCKS5_PORT: in mtprotoproxy.py (line 325) won't activate SOCKS5 mode even though port 0 was specified. While port 0 is unusual, if specified, it should either be rejected with an error or properly handled.

Consider validating the port range explicitly:

SOCKS5_PORT = int(os.environ.get("SOCKS5_PORT", 0)) if os.environ.get("SOCKS5_PORT", "").isdigit() and int(os.environ.get("SOCKS5_PORT", 0)) > 0 else None
Suggested change
SOCKS5_PORT = int(os.environ.get("SOCKS5_PORT", 0)) if os.environ.get("SOCKS5_PORT", "").isdigit() else None
SOCKS5_PORT = (
int(os.environ.get("SOCKS5_PORT", 0))
if os.environ.get("SOCKS5_PORT", "").isdigit()
and 1 <= int(os.environ.get("SOCKS5_PORT", 0)) <= 65535
else None
)

Copilot uses AI. Check for mistakes.
SOCKS5_USER = os.environ.get("SOCKS5_USER", None)
SOCKS5_PASS = os.environ.get("SOCKS5_PASS", None)
Loading