Complete Tutorial of Trojan Deployment via Docker and Caddy

Complete Tutorial of Trojan Deployment via Docker and Caddy

Trojan is a novel circumvention protocol. It claims to have adopted an unrecognizable mechanism to bypass GFW or any Internet blocks. It adopts a TLS-based protocol to avoid DPI recognition and QOS, and disguises the most common network protocol on the Internet.

The principle is simple to understand: Assuming that Trojan-Server is listening on port 443 of the server, then for normal requests from the Trojan-Client, it will directly connect to the Internet. If it is another port 443 data request, it will forward the data on the server to the service running on local port 80, and then access Internet data.

This tutorial mainly introduces the use of docker to deploy this Trojan protocol, which uses the acme.sh script to apply for a certificate, and uses Caddy as a web service to receive the request data forwarded by Trojan.

Preparation:

  • VPS
  • Your own domain
  • Basic understanding of Linux

So let’s start!

1. Certificate Configuration

1.1 Install acme.sh script

Install socat

apt-get update && apt-get -y install socat

Install script

wget -qO- get.acme.sh | bash
source ~/.bashrc
1.2 Apply for a certificate for the domain name

Add a record to your DNS service provider. Assuming your domain name is yourdomain.com. IMPORTANT: Do not activate CDN (such as Cloudfare, Cloudfront)

acme.sh --issue --standalone -d yourdomain.com -k ec-256

Note: The certificates and keys applied by the script are stored in the directory: /root/.acme.sh/example.com_ecc

1.3 Install the certificate to the specified location

Create Trojan directory

mkdir /etc/trojan

Install the certificate and private key to the specified location

acme.sh --installcert -d yourdomain.com --fullchain-file /etc/trojan/trojan.crt --key-file /etc/trojan/trojan.key --ecc

2. Caddy Installation and Configuration

2.1 Install Caddy
wget -qO- https://getcaddy.com | bash -s personal

Locate Caddy

which caddy

If you see the following output, you are on the track.

/usr/local/bin/caddy
2.2 Create Caddy configuration file

2.2.1 Create Caddy directory

Create Caddy directory and switch to it

mkdir /root/caddy && cd /root/caddy

2.2.2 Create Caddy configuration file: Caddyfile

Create and edit Caddyfile

nano Caddyfile

The following is the content. Please modify and add it to the file.

yourdomain.com:80 {
gzip
log /root/caddy/caddy.log
proxy / https://baidu.com
}

Note: Here proxy / https://baidu.com is used to replace other websites. You can either (1) replace it with any unblocked website, (2) remove this line and use root /path/to/website to specify the root directory of the website.

2.3 Register Caddy service

Switch to the directory and edit service file

cd /etc/systemd/system && vim caddy.service

The following is the content. Please add it to the file.

[Unit]
Description=Caddy Service
After=network.target 
[Service]
ExecStart=/usr/local/bin/caddy -conf /root/caddy/Caddyfile
Restart=on-abort
LimitNOFILE=1048576 
[Install]
WantedBy=multi-user.target

Reload daemon

systemctl daemon-reload

Start caddy service

systemctl start caddy

Check the running status of caddy service (quit by enter q)

systemctl status caddy

(optional) Add caddy service to start from boot

systemctl enable caddy
2.4 (optional) Apply for HTTPS certificate manually

In Step 2.3, after running “systemctl status caddy”, some users may have problem of (…) failed to obtain certificate: acme: error: 429 :: POST (…)This is because “too many failed authorizations recently”. (https://caddyserver.com/v1/docs/http.ratelimit) One option is of course waiting for 7 days and retry. The other solution is to apply for HTTPS certificate manually.

Caddy is a simple and easy-to-use web server. By default, Caddy will directly apply letsencrypt certificate for our domain name. However, for some reasons, letsencrypt may not be able to access our server. At this time, you need to manually apply for a certificate.

Assuming your website is already with SSL/TLS certificates. You can edit Caddy file and set cert/key path manually(adding two lines).

cd /root/caddy && nano Caddyfile

Adding cert path (assuming you are using the default path, or you should modify yourself)

www.yourdomain.com:80 {
gzip
tls /etc/letsencrypt/live/www.yourdomain.com/cert.pem
tls /etc/letsencrypt/live/www.yourdomain.com/privkey.pem
log /root/caddy/caddy.log
proxy / https://baidu.com
}

Restart Caddy

caddy --conf=Caddyfile

Make sure port is available.


3. Start Trojan Service with Docker

3.1 Install and configure docker

Install docker

wget -qO- get.docker.com | bash

Start docker service

systemctl start docker

Check the running status of docker service

systemctl status docker

Check docker version

docker -v

(optional) Add docker service to start from boot

systemctl enable docker
3.2 Pull trojan image

There are multiple images available. Here’s one of them I preferred.

docker pull teddysun/trojan
3.3 Create trojan-server configuration file

Switch to the trojan directory and edit configuration file

cd /etc/trojan && nano config.json

The following is the default content.

{
"run_type": "server",
"local_addr": "0.0.0.0",
"local_port": 443,
"remote_addr": "127.0.0.1",
"remote_port": 80,
"password": [
"trojanuser1",
"trojanuser2"
],
"log_level": 1,
"ssl": {
"cert": "/etc/trojan/trojan.crt",
"key": "/etc/trojan/trojan.key",
"key_password": "",
"cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384",
"cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
"prefer_server_cipher": true,
"alpn": [
"http/1.1"
],
"reuse_session": true,
"session_ticket": false,
"session_timeout": 600,
"plain_http_response": "",
"curves": "",
"dhparam": ""
},
"tcp": {
"prefer_ipv4": false,
"no_delay": true,
"keep_alive": true,
"reuse_port": false,
"fast_open": false,
"fast_open_qlen": 20
},
"mysql": {
"enabled": false,
"server_addr": "127.0.0.1",
"server_port": 3306,
"database": "trojan",
"username": "trojan",
"password": ""
}
}

Note: You can set multiple passwords to facilitate multiple users. For the specific configuration file, the trojan project gives a detailed explanation: https://trojan-gfw.github.io/trojan/config

3.4 Start docker container
docker run -d --name trojan --restart always --net host -v /etc/trojan:/etc/trojan teddysun/trojan

Note: The purpose of using –net host to specify the container applying the host network, is to allow it to access 127.0.0.1 to the server, and forward data to caddy. There is another method, instead of –net host, use -p 443:443 to map port 443, but in the configuration file of the previous step, you need to modify “remote_addr”: “127.0.0.1” and change it to “remote_addr” : “Your server IP or your domain name”.


4. Client Configuration

Trojan client is not as nice as V2Ray for beginners, but everything is fully functional.

4.1 Windows, MacOS, and Linux

Go to trojan releases to download the latest package. After decompression, edit config.json file.

Releases address: https://github.com/trojan-gfw/trojan/releases

Default configuration file as follows

{
"run_type": "client",
"local_addr": "127.0.0.1",
"local_port": 1080,
"remote_addr": "yourdomain.com",
"remote_port": 443,
"password": [
"trojanuser1"
],
"log_level": 1,
"ssl": {
"verify": true,
"verify_hostname": true,
"cert": "",
"cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
"cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
"sni": "",
"alpn": [
"h2",
"http/1.1"
],
"reuse_session": true,
"session_ticket": false,
"curves": ""
},
"tcp": {
"no_delay": true,
"keep_alive": true,
"reuse_port": false,
"fast_open": false,
"fast_open_qlen": 20
}
}

Note: Here you need to modify “remote_addr” to your domain name and one of the passwords you set in Step 3.3. After configuration, start trojan. Currently(as of today), the trojan client is relatively simple and needs to be paired with a browser plug-in.

4.2 iOS

It is recommended to use Shadowrocket, which can directly configure the trojan protocol.

4.3 Android (haven’t tested by me)

Trojan author has also made a software for the Android side, called Igniter, which can be used to add and use trojan nodes. Download address: https://github.com/trojan-gfw/igniter/releases

Although this software is still in the testing stage, the author has released a lot of pre-compiled versions. You can download the app-release.apk file in the above link.

  • Server: yourdomain.com
  • Port: 443
  • Password: trojanuser1
  • Enable IPv6: optional
  • Verify Certificate: Because it uses a CA certificate, it is recommended to turn it on here. If it is a self-signed certificate, it’s optional
4.4 Browser Plugin Configuration

Here I take Chrome as an example. Extension named SwitchyOmega is recommended. Go to proxy tab and setup:

  • Protocol: SOCKS5
  • Server: 127.0.0.1
  • Port: 1080 (matching settings in trojan-client)

5. Conclusion

Applications of Docker are growing, for its continuous integration, version control, portability, isolation and security. Although I already have V2Ray configured, deploying Trojan with Docker offers me an alternative. And it’s fun.


Copyright statement: Unless otherwise stated, all articles on this blog adopt the CC BY-NC-SA 4.0 license agreement. For non-commercial reprints and citations, please indicate the author: Henry, and original article URL. For commercial reprints, please contact the author for authorization.