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.