The Ultimate Stealth Proxy: Hiding Trojan-Go Inside a Live WordPress Blog

In the world of internet freedom, encryption is no longer enough; you need camouflage. This guide demonstrates how to deploy a Trojan-Go proxy behind a fully functional WordPress site, creating a setup that is statistically indistinguishable from a standard web service. By using Path Multiplexing, we ensure that your proxy traffic blends into the background noise of legitimate API calls and blog browsing.

I. Phase One: The Backend (Apache Decoy)

Apache will act as the “decoy” server, providing the real content that hides your proxy.

1. Install & Enable Modules

sudo apt update && sudo apt install apache2 -y
# Enable modules for proxying and header manipulation
sudo a2enmod proxy proxy_http headers rewrite

2. Configure Ports

Edit /etc/apache2/ports.conf using vim:

  • Keep: Listen 80 and Listen 1234 (or your chosen internal port).
  • Remove/Comment: Listen 443 (This must be handled by Trojan-Go).

3. Create the VirtualHost

sudo vim /etc/apache2/sites-available/stealth-site.conf

<VirtualHost *:1234>
    ServerName www.yourdomain.com
    DocumentRoot /var/www/html/your_folder

    # IMPORTANT: Trojan-Go handles decryption, so SSL is OFF here
    SSLEngine off

    # THE FIX: Tell WordPress the original request was HTTPS
    # This prevents the infinite redirect loop
    RequestHeader set X-Forwarded-Proto "https"

    <Directory /var/www/html/your_folder>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

sudo a2ensite stealth-site.conf && sudo systemctl restart apache2

II. Phase Two: WordPress Compatibility Fix

WordPress will trigger a “Too Many Redirects” error if it doesn’t realize it’s behind a proxy.

Edit wp-config.php and insert this snippet at the very top, immediately after the <?php tag:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}

define('WP_HOME', 'https://www.yourdomain.com/blog');
define('WP_SITEURL', 'https://www.yourdomain.com/blog');

III. Phase Three: The Proxy Gateway (Trojan-Go)

1. Configuration

Create /etc/trojan-go/config.json:

{
    "run_type": "server",
    "local_addr": "0.0.0.0",
    "local_port": 443,
    "remote_addr": "127.0.0.1",
    "remote_port": 1234,
    "password": ["your_password_here"],
    "ssl": {
        "cert": "/etc/letsencrypt/live/yourdomain.com/fullchain.pem",
        "key": "/etc/letsencrypt/live/yourdomain.com/privkey.pem",
        "sni": "yourdomain.com"
    },
    "websocket": {
        "enabled": true,
        "path": "/api/v2/updates"
    }
}

2. Deploy the “Bait” Page

Create the actual directory for your secret path to satisfy manual probes:

mkdir -p /var/www/html/your_folder/api/v2/updates
vim /var/www/html/your_folder/api/v2/updates/index.html

Insert: {"status":"online","message":"API endpoint active"}

IV. Phase Four: Troubleshooting (The “Field Manual”)

1. The SSL Conflict (Bad Request)

  • Error: “Speaking plain HTTP to an SSL-enabled server port.”
  • Fix: Certbot often creates *-le-ssl.conf files in sites-enabled. You must disable them: sudo a2dissite *-le-ssl.conf. Only your custom port 1234 config should be active for that domain.

2. The Redirect Loop

  • Fix: Ensure the PHP code in wp-config.php is at the absolute top. If it’s below the database definitions, it might be ignored. Clear your browser HSTS cache via chrome://net-internals/#hsts.

To ensure your server remains resilient after a reboot, you must wrap Trojan-Go in a Systemd service. This ensures the proxy starts automatically and restarts itself if it crashes.

Here is the final section to complete your deployment manual.

V. Phase Five: Persistence (Systemd Service)

Running the binary manually is for testing; for production, you need a background service.

1. Create the Service File

sudo vim /etc/systemd/system/trojan-go.service

2. Paste the Configuration

Copy and paste the following, ensuring the paths to your binary and config are correct:

[Unit]
Description=Trojan-Go Proxy Server
After=network.target nss-lookup.target

[Service]
Type=simple
StandardError=journal
# Change these paths if your binary or config are located elsewhere
ExecStart=/usr/local/bin/trojan-go -config /etc/trojan-go/config.json
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

3. Enable and Start

# Reload systemd to recognize the new service
sudo systemctl daemon-reload

# Start the service now
sudo systemctl start trojan-go

# Enable the service to start on boot
sudo systemctl enable trojan-go

# Check the status to ensure it's "active (running)"
sudo systemctl status trojan-go

VI. Final Verification Checklist

Before you close the terminal, run these three commands to ensure the “Invisible Proxy” is perfect:

  1. Check Port 443: sudo ss -tulpn | grep :443It should be owned by trojan-go.
  2. Check Port 1234: sudo ss -tulpn | grep :1234It should be owned by apache2.
  3. Test the Decoy: Visit https://yourdomain.com/api/v2/updates in a browser.You should see your dummy JSON/HTML message, not a 404 or a Trojan error.

EX-I. Post-Deployment Summary

This setup creates a protocol-level illusion:

Traffic SourceRequest TypeServer ResponseVisual Result
Censor/AuditorHTTPS GETApache (via Trojan)A real blog or API status page.
ShadowrocketWebSocket UpgradeTrojan-GoA secure, high-speed tunnel.
Random ScannerDirect IP ScanTimeout/404No “Proxy” signature detected.

By using X-Forwarded-Proto in Apache and $_SERVER['HTTPS'] = 'on' in WordPress, you’ve bridged the gap between a secure proxy gateway and a standard web application. You are now officially hiding in plain sight.

EX-II. Advanced Defense Analysis

Path Multiplexing & Behavioral Camouflage

The genius of this setup lies in the behavior of the /api/v2/updates path:

  • Standard GET Request: Trojan-Go ignores it → Apache serves a JSON/HTML status page. (Status 200).
  • Authorized WebSocket Handshake: Trojan-Go intercepts it → Tunnel opens. (Status 101).

Fingerprint Matching: Proxy traffic consists of long-lived WebSocket streams. By using an “API Updates” path, your long-lived connection is statistically explained away as a standard data sync between a client and a server. This is the ultimate “Double-Agent” configuration: real content as the best armor.

sudo certbot renew --post-hook "systemctl restart trojan-go apache2"