ADDED Requirements
Requirement: Trojan users are configured via YAML file
The trojan role SHALL read user credentials from a users.yml file located at the playbook root. The file SHALL define a trojan_users list where each entry contains name and password fields.
Scenario: Users file exists with multiple entries
- WHEN
users.yml contains trojan_users with entries [{name: alice, password: pass1}, {name: bob, password: pass2}]
- THEN the Trojan configuration includes both users
Scenario: Users file is missing
- WHEN
users.yml does not exist and no trojan_users variable is defined elsewhere
- THEN the playbook fails with a clear error message
Scenario: Users file is gitignored
- WHEN the repository is inspected
- THEN
.gitignore contains an entry for users.yml
Requirement: Trojan binary is installed
The trojan role SHALL download and install the trojan-go binary from release artifacts to /usr/local/bin/trojan-go. The version SHALL be configurable via trojan_version.
Scenario: Fresh installation
- WHEN the trojan role runs on a server without trojan-go installed
- THEN the specified version of the binary is downloaded and installed
- THEN the binary is executable
Scenario: Version upgrade
- WHEN
trojan_version is changed and the playbook is re-run
- THEN the binary is replaced with the new version
- THEN the Trojan service is restarted
Requirement: TLS certificate is provisioned via Let's Encrypt
The trojan role SHALL use certbot to obtain a TLS certificate for the configured domain. After provisioning or renewal, the certificate and key SHALL be copied to /etc/trojan-go/tls/ so the service user can read them.
Scenario: Certificate provisioning
- WHEN the trojan role runs with a configured
trojan_domain
- THEN certbot obtains a TLS certificate for that domain
- THEN the certificate and key are copied to
/etc/trojan-go/tls/ owned by the trojan service user
Scenario: Certificate auto-renewal
- WHEN the certificate is within 30 days of expiry
- THEN certbot renews it automatically
- THEN a deploy-hook copies the renewed certs to
/etc/trojan-go/tls/
- THEN the Trojan service is reloaded after renewal
Requirement: Trojan runs as a systemd service
The trojan role SHALL create a systemd unit file for trojan-go and ensure it is enabled and started. The unit SHALL include both AmbientCapabilities and CapabilityBoundingSet for CAP_NET_BIND_SERVICE.
Scenario: Service is running
- WHEN the trojan role completes
- THEN the Trojan systemd service is enabled and running
- THEN the service runs under a dedicated non-root user
- THEN the service user can read the TLS certificate and key files
Requirement: Trojan listens on port 443 with TLS
The Trojan service SHALL listen on port 443 and terminate TLS using the Let's Encrypt certificate.
Scenario: Trojan accepts connections on 443
- WHEN a Trojan client connects to port 443 with valid credentials
- THEN the connection is accepted and proxied
Scenario: Non-Trojan traffic is handled by fallback
- WHEN a non-Trojan HTTPS request arrives on port 443
- THEN Trojan forwards it to a local fallback endpoint (if configured)
Requirement: Trojan configuration is templated
The trojan role SHALL generate a JSON configuration file from a Jinja2 template. The config SHALL include: run_type, local_addr, local_port, remote_addr, remote_port, password array (from trojan_users), ssl section with cert/key paths, and log_level.
Scenario: Multi-user configuration is generated
- WHEN the trojan role runs with multiple users defined
- THEN the config file contains a
password array with all user passwords
- THEN each user can authenticate with their respective password
Scenario: Configuration change triggers restart
- WHEN
users.yml or trojan variables are changed and the playbook is re-run
- THEN the configuration file is updated
- THEN the Trojan service is restarted via handler
Requirement: Trojan port 443 is allowed through UFW
The trojan role SHALL allow port 443 through UFW.
Scenario: Firewall allows HTTPS port
- WHEN the trojan role runs
- THEN UFW allows incoming TCP traffic on port 443