No Description

kotoyuuko 5cfdf80ecc chore: make group_vars into templates, gitignore instances 3 weeks ago
.claude 25e4e8d0aa chore: add OpenSpec commands and skills, gitignore local settings 3 weeks ago
group_vars 5cfdf80ecc chore: make group_vars into templates, gitignore instances 3 weeks ago
inventory 447495663f chore: make inventory a template, gitignore the instance 3 weeks ago
openspec 5cfdf80ecc chore: make group_vars into templates, gitignore instances 3 weeks ago
roles 97025df341 feat: add geoblock role to drop outbound traffic to China IPs 3 weeks ago
templates 1a97d299df feat: auto-generate random ports/passwords and render Surge config 3 weeks ago
.gitignore 5cfdf80ecc chore: make group_vars into templates, gitignore instances 3 weeks ago
README.md 5cfdf80ecc chore: make group_vars into templates, gitignore instances 3 weeks ago
ansible.cfg 7d72410741 feat: ansible chained proxy setup with shadowsocks + trojan 3 weeks ago
site.yml 1a97d299df feat: auto-generate random ports/passwords and render Surge config 3 weeks ago

README.md

Ansible Proxy Chain

Ansible playbook for provisioning a two-server chained proxy setup:

  • Relay server (中转机): Shadowsocks-rust — handles general traffic
  • Landing server (落地机): Trojan-Go — handles AI/streaming services requiring local IP

Client-side Surge uses underlying-proxy to chain connections:

Client → Relay (SS) → Landing (Trojan) → Internet   # chained
Client → Landing (Trojan) → Internet                 # direct
Client → Relay (SS) → Internet                       # relay only

Prerequisites

  • Two servers running Ubuntu/Debian
  • A domain name pointing to the landing server (for Trojan TLS)
  • Ansible 2.12+ on your local machine
  • community.general Ansible collection: ansible-galaxy collection install community.general

Setup

1. Configure inventory

cp inventory/hosts.yml.example inventory/hosts.yml

Edit inventory/hosts.yml with your server IPs and SSH user:

all:
  children:
    relay:
      hosts:
        relay-server:
          ansible_host: "1.2.3.4"
          ansible_user: "ubuntu"   # or "root"
    landing:
      hosts:
        landing-server:
          ansible_host: "5.6.7.8"
          ansible_user: "ubuntu"   # or "root"

SSH user options:

  • Root: Set ansible_user: "root" — connects directly as root
  • Non-root: Set ansible_user: "ubuntu" (or any user) — requires passwordless sudo on the server. If sudo requires a password, add --ask-become-pass when running the playbook

Make sure your SSH key is already configured for the specified user on both servers.

2. Configure variables

for f in group_vars/*.yml.example; do cp "$f" "${f%.example}"; done

Edit group_vars/landing.yml:

  • trojan_domain: Your domain name
  • certbot_email: Email for Let's Encrypt notifications

Ports and passwords are auto-generated on first run and persisted in credentials/. No manual password setup needed.

To override auto-generated values:

ansible-playbook site.yml --extra-vars "ss_password=my-custom-pass ss_port=12345"

3. Run the playbook

ansible-playbook site.yml

After deployment, the Surge client config is generated at output/surge-client.conf with all connection parameters filled in. Import this file into Surge directly.

4. Backup credentials

The credentials/ directory contains auto-generated passwords and ports. Back it up — if lost, new credentials will be generated and servers must be re-provisioned.

cp -r credentials/ /path/to/backup/

Project Structure

├── ansible.cfg
├── inventory/
│   └── hosts.yml
├── group_vars/
│   ├── all.yml
│   ├── relay.yml
│   └── landing.yml
├── roles/
│   ├── base/           # SSH hardening, UFW, fail2ban
│   ├── geoblock/       # Block outbound to China IPs
│   ├── shadowsocks/    # shadowsocks-rust (relay)
│   └── trojan/         # trojan-go + certbot (landing)
├── templates/
│   └── surge-client.conf.j2
├── credentials/        # Auto-generated (gitignored)
├── output/             # Generated Surge config (gitignored)
└── site.yml

Variables Reference

Variable Default Description
ss_port auto-generated (10000–49999) Shadowsocks listen port
ss_cipher aes-256-gcm Shadowsocks encryption method
ss_password auto-generated (32 chars) Shadowsocks password
ss_version 1.21.2 shadowsocks-rust release version
trojan_port 443 (fixed) Trojan listen port
trojan_domain Domain name for TLS certificate
trojan_password auto-generated (32 chars) Trojan password
trojan_fallback_port 8080 Fallback port for non-Trojan traffic
trojan_version 0.10.6 trojan-go release version
certbot_email Email for Let's Encrypt
ssh_port 22 SSH listen port