Terraform script to deploy X-Ray VPN server on AWS with automatic TLS certificate provisioning.
- Automated X-Ray VPN server deployment on AWS
- Let's Encrypt TLS certificate automation
- Dynamic DNS integration with DuckDNS or Cloudflare
- WebSocket transport with TLS
- Configurable for multiple server instances
- Terraform CLI (1.3.9+) installed
- AWS CLI installed
- AWS account with appropriate permissions
- Either a DuckDNS or Cloudflare account (see setup instructions below)
- SSH key pair generated
-
Create AWS Access Keys
- Log into your AWS Console
- Go to IAM → Users → Your User → Security credentials
- Create a new Access Key and note down the Access Key ID and Secret Access Key
-
Configure AWS Profile Create or edit
~/.aws/credentials
file with your AWS credentials:[xray_profile] aws_access_key_id = YOUR_ACCESS_KEY_ID aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
Alternatively, you can set a different profile name in
terraform.tfvars
:profile = "your-custom-profile-name"
-
Create DuckDNS Account
- Visit DuckDNS.org
- Sign in with your preferred account (Google, GitHub, etc.)
-
Create a Subdomain
- On the DuckDNS dashboard, enter your desired subdomain name
- Click "add domain" (e.g., if you enter "myserver", you'll get "myserver.duckdns.org")
- Note down your full domain name
-
Get Your Token
- Your DuckDNS token is displayed at the top of the dashboard page
- Copy this token - you'll need it for the
terraform.tfvars
file
-
Test Your Setup (Optional) You can test your DuckDNS setup by running:
curl "https://www.duckdns.org/update?domains=YOUR_DUCKDNS_DOMAIN&token=YOUR_DUCKDNS_TOKEN&ip=1.2.3.4"
-
Get a Cloudflare API Token
- Log into your Cloudflare account.
- Go to My Profile → API Tokens.
- Create a new API token with the following permissions:
- Zone → DNS → Edit
- Copy the generated token.
-
Add Your Domain to Cloudflare
- Ensure your domain is added to your Cloudflare account.
- Note down your domain name (e.g.,
example.com
).
-
Configure Variables In your
terraform.tfvars
file, add the following:cloudflare_api_token = "your-cloudflare-api-token" cloudflare_domain = "yourdomain.com" cloudflare_subdomain = "app" # Optional, default is "app"
-
Clone and Configure
git clone https://github.com/mmshad/xray-aws-terraform.git cd xray-aws-terraform cp terraform.tfvars.example terraform.tfvars
-
Edit Configuration Edit
terraform.tfvars
with your values:# For DuckDNS duckdns_domain = "your-subdomain.duckdns.org" # Your DuckDNS domain from setup above certbot_email = "your-email@example.com" # Email for Let's Encrypt certificates duckdns_token = "your-duckdns-token" # DuckDNS token from your dashboard # For Cloudflare cloudflare_api_token = "your-cloudflare-api-token" cloudflare_domain = "yourdomain.com" cloudflare_subdomain = "app" # Optional, default is "app"
-
Deploy
terraform init terraform validate terraform plan terraform apply
-
Get Connection Details After deployment, look for the green connection link in the output:
- For VMESS protocol:
vmess://
link - For VLESS protocol:
vless://
link
Copy this link to your V2Ray/X-Ray client.
- For VMESS protocol:
duckdns_domain
: Your DuckDNS domain (e.g., "myserver.duckdns.org") or Cloudflare domain (e.g., "example.com")certbot_email
: Email for Let's Encrypt certificate registration - used for certificate renewal notificationsduckdns_token
: Your DuckDNS token for DNS updates - found on your DuckDNS dashboardcloudflare_api_token
: Your Cloudflare API token for DNS updatescloudflare_domain
: Your Cloudflare domain namecloudflare_subdomain
: Subdomain for Cloudflare (default: "app")
region
: AWS region (default: "us-east-1")ec2_count
: Number of VPN servers (default: 1)instance_type
: EC2 instance type (default: "t2.micro")Note:
t2.micro
may not be available in all AWS regions. If you encounter availability issues, consider usingt3.micro
which offers better performance but may come with slightly higher costs. For example,t2.micro
is not available ineu-north-1
.protocol
: X-Ray protocol to use - either "vmess" or "vless" (default: "vmess")profile
: AWS CLI profile name (default: "xray_profile")
To deploy multiple VPN servers, set ec2_count
in your terraform.tfvars
:
ec2_count = 3
Each server will have its own connection link in the output.
To deploy multiple VPN servers, set ec2_count
in your terraform.tfvars
:
ec2_count = 3
Each server will automatically be assigned a unique subdomain based on the base_subdomain
variable. For example, if base_subdomain
is set to app
, the servers will use the subdomains app1
, app2
, and app3
.
base_subdomain = "app" # Base subdomain for VPN servers
ec2_count = 3 # Number of servers to deploy
After deployment, each server's connection link will be displayed in the output, using its unique subdomain.
This project supports both VMESS and VLESS protocols:
- More widely supported by V2Ray clients
- Uses legacy protocol with additional encryption layer
- Recommended for maximum compatibility
- Newer, more efficient protocol
- Better performance with lower overhead
- Requires newer V2Ray/Xray clients
To use VLESS instead of VMESS, add this line to your terraform.tfvars
:
protocol = "vless"
The deployment will automatically generate the appropriate connection link (vmess://
or vless://
) based on your selection.
- All traffic is encrypted with TLS
- Random ports are assigned for each deployment
- SSH access is available for troubleshooting
- Security groups allow necessary ports only
To destroy the infrastructure:
terraform plan -destroy
terraform destroy
- Ensure your DuckDNS or Cloudflare credentials are correct
- Verify AWS credentials are properly configured
- Check AWS service quotas for EC2 instances
- DNS propagation may take a few minutes
This project is licensed under the MIT License.
Pull requests are welcome. For major changes, please open an issue first.