A Discord bot that controls AWS EC2 instances and manages game servers via a Pterodactyl panel. Users can start/stop EC2 instances, check status, and monitor server uptime through Discord commands.
- Start/stop AWS EC2 instances via Discord commands
- Monitor instance status and uptime
- Track daily and total uptime statistics
- Integration with Pterodactyl panel for game server management
- Persistent SQLite database for uptime tracking
- Docker support with data persistence
Starting from zero? Follow these steps in order:
-
☐ AWS Account Setup (see detailed instructions below)
- Create AWS account
- Create IAM user with limited permissions
- Save Access Key ID and Secret Access Key
-
☐ EC2 Instance Setup
- Launch EC2 instance in your preferred region
- Tag instance with key=
guild, value=YOUR_DISCORD_GUILD_ID - Note the Instance ID
- Update IAM policy with Instance ID
-
☐ Discord Bot Setup
- Create Discord application & bot user
- Save bot token
- Enable required intents
- Invite bot to your Discord server
- Get your Discord Guild ID (Server ID)
-
☐ Deploy Bot
- Clone this repository
- Copy
.env.exampleto.env - Fill in all credentials in
.env - Run
docker-compose up -d
-
☐ Test
- Type
.pingin Discord - Type
.stateto check instance state - Type
.startto start your instance
- Type
Estimated Setup Time: 30-45 minutes for first-time setup
- Docker and Docker Compose (for containerized deployment)
- OR Python 3.10+ (for local deployment)
- AWS Account (instructions below for complete setup)
- Discord Bot Token (instructions below)
- Pterodactyl Panel (optional, for game server management)
This section guides you through setting up AWS from nothing to having a controllable EC2 instance.
- Go to https://aws.amazon.com
- Click "Create an AWS Account"
- Follow the registration process (requires credit card, but Free Tier available)
- Sign in to the AWS Management Console
For security, create a dedicated IAM user with restricted permissions instead of using root credentials.
-
Navigate to IAM Console
- Go to IAM Console
- Click "Users" in the left sidebar
- Click "Add users"
-
Configure User
- User name:
ec2-discord-bot(or your preferred name) - Select "Access key - Programmatic access"
- Click "Next: Permissions"
- User name:
-
Create Custom Policy
- Click "Attach policies directly"
- Click "Create policy"
- Click the "JSON" tab
- Paste the following policy (replace
YOUR_REGIONandYOUR_INSTANCE_IDafter creating the instance):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2InstanceControl",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:RebootInstances"
],
"Resource": "arn:aws:ec2:YOUR_REGION:*:instance/YOUR_INSTANCE_ID"
},
{
"Sid": "EC2DescribeAll",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeTags"
],
"Resource": "*"
}
]
}-
Name and Create Policy
- Click "Next: Tags" (skip tags)
- Click "Next: Review"
- Name:
EC2DiscordBotPolicy - Description: "Allows Discord bot to control specific EC2 instance"
- Click "Create policy"
-
Attach Policy to User
- Go back to the user creation tab
- Refresh the policy list
- Search for
EC2DiscordBotPolicy - Check the box next to it
- Click "Next: Tags" (optional)
- Click "Next: Review"
- Click "Create user"
-
Save Credentials
- IMPORTANT: Copy the Access Key ID and Secret Access Key
- Download the CSV or save them securely
- You won't be able to see the secret key again!
-
Navigate to EC2 Console
- Go to EC2 Console
- Select your preferred region (top-right dropdown)
- Click "Launch Instance"
-
Configure Instance
Name and Tags:
- Name:
minecraft-server(or your preferred name) - Click "Add additional tags"
- Add tag: Key =
guild, Value =YOUR_DISCORD_GUILD_ID⚠️ CRITICAL: This tag must match your Discord Guild ID exactly- To find your Guild ID: Enable Developer Mode in Discord (User Settings > Advanced), right-click your server, "Copy ID"
Application and OS Images (AMI):
- Choose "Amazon Linux 2023" or "Ubuntu Server 22.04 LTS"
- Both are Free Tier eligible
Instance Type:
- Select
t2.micro(Free Tier) ort3a.small(better performance, ~$15/month) - For game servers: Minimum
t3.smallrecommended
Key Pair (login):
- Click "Create new key pair"
- Name:
ec2-discord-bot-key - Type: RSA
- Format:
.pem(Linux/Mac) or.ppk(Windows/PuTTY) - Click "Create key pair" and save the file securely
Network Settings:
- Click "Edit"
- Auto-assign public IP: Enable
- Firewall (security group): Create new
- Security group name:
ec2-discord-bot-sg - Description: "Security group for Discord bot controlled instance"
Security Group Rules:
- SSH (22): Your IP (for administration)
- Custom TCP (25565): 0.0.0.0/0 (for Minecraft, if applicable)
- Add rules for your specific game server ports
- Click "Add security group rule" for each port needed
Storage:
- 8 GB gp3 (Free Tier) or increase for game servers (20-30 GB recommended)
- Name:
-
Review and Launch
- Review all settings
- Click "Launch Instance"
- Wait for instance to start (2-3 minutes)
- Note the Instance ID (e.g.,
i-1234567890abcdef0)
Now that you have an Instance ID, update the IAM policy:
- Go back to IAM Console
- Click "Policies" in the left sidebar
- Search for
EC2DiscordBotPolicy - Click the policy name
- Click "Edit policy"
- Click "JSON" tab
- Replace
YOUR_REGIONwith your region (e.g.,us-east-1) - Replace
YOUR_INSTANCE_IDwith your actual instance ID - Click "Next: Review"
- Click "Save changes"
Critical: Ensure your instance has the correct tag!
# Using AWS CLI (if installed)
aws ec2 describe-instances --instance-ids YOUR_INSTANCE_ID --query 'Reservations[0].Instances[0].Tags'
# Expected output should include:
# {
# "Key": "guild",
# "Value": "YOUR_DISCORD_GUILD_ID"
# }Or via Console:
- Go to EC2 Console
- Click "Instances"
- Select your instance
- Check the "Tags" tab
- Verify
guildtag exists with correct Guild ID
Before proceeding, verify your IAM credentials work:
# Set credentials temporarily
export AWS_ACCESS_KEY_ID=your_access_key_here
export AWS_SECRET_ACCESS_KEY=your_secret_key_here
export AWS_DEFAULT_REGION=your_region_here
# Test credentials
aws sts get-caller-identity
# Test instance access
aws ec2 describe-instances --instance-ids YOUR_INSTANCE_ID
# Test start/stop (optional)
aws ec2 stop-instances --instance-ids YOUR_INSTANCE_ID
aws ec2 start-instances --instance-ids YOUR_INSTANCE_ID- Open Discord
- Go to User Settings (⚙️ icon)
- Go to "Advanced"
- Enable "Developer Mode"
- Close settings
- Right-click your Discord server icon
- Click "Copy ID"
- This is your Guild ID - save it for configuration
You now have:
- ✅ IAM user with programmatic access
- ✅ Restricted IAM policy for security
- ✅ EC2 instance tagged with your Guild ID
- ✅ Security group configured
- ✅ Access credentials ready
Next Steps: Set up your Discord bot below.
- Go to Discord Developer Portal
- Click "New Application"
- Name your application (e.g., "EC2 Controller Bot")
- Click "Create"
- In your application, click "Bot" in the left sidebar
- Click "Add Bot"
- Confirm by clicking "Yes, do it!"
- Under "Token", click "Copy" to copy your bot token
⚠️ IMPORTANT: Save this token securely - you'll need it for configuration- Never share this token publicly!
- Scroll down to "Privileged Gateway Intents"
- Enable the following (optional, but recommended):
- "Server Members Intent" (for member verification)
- "Message Content Intent" (to read commands)
- Click "OAuth2" > "URL Generator" in the left sidebar
- In "Scopes", check:
botapplications.commands
- In "Bot Permissions", check:
Read Messages/View ChannelsSend MessagesEmbed LinksRead Message History
- Copy the generated URL at the bottom
- Open the URL in a browser
- Select your Discord server
- Click "Authorize"
- Complete the CAPTCHA
Your bot is now in your Discord server and ready to be configured.
git clone <your-repo-url>
cd aws_ec2_discord_controllerCopy the example environment file and edit it with your credentials:
cp .env.example .env
nano .env # or use your preferred editorEdit .env and fill in ALL the following values with credentials from the setup steps above:
# ===== REQUIRED: Discord Bot Configuration =====
# Get this from Discord Developer Portal (Step 2 of Discord Bot Setup)
AWSDISCORDTOKEN=your_discord_bot_token_here
# ===== REQUIRED: AWS Configuration =====
# Get these from IAM User creation (Step 2 of AWS Setup)
AWS_ACCESS_KEY_ID=your_aws_access_key_id_from_iam
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key_from_iam
AWS_DEFAULT_REGION=us-east-1 # Use the region where you created your EC2 instance
# ===== REQUIRED: Discord Guild Configuration =====
# Get this from Discord (Step 7 of AWS Setup)
guild_id=your_discord_guild_id_here
# ===== OPTIONAL: Pterodactyl Panel Configuration =====
# Only needed if you're managing game servers via Pterodactyl
# Leave as defaults if not using Pterodactyl
api=your_pterodactyl_api_key_here
accept_type=application/json
content_type=application/json
panel_url=https://your-panel-domain.com
get_server_url=https://your-panel-domain.com/api/client
# ===== Database Configuration (leave as default for Docker) =====
DB_PATH=/data/ec2bot.dbExample filled out .env (with dummy values):
AWSDISCORDTOKEN=YOUR_BOT_TOKEN_GOES_HERE_FROM_DISCORD_DEVELOPER_PORTAL
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION=us-east-1
guild_id=123456789012345678
api=ptla_exampleapikeyhere123456789
accept_type=application/json
content_type=application/json
panel_url=https://panel.example.com
get_server_url=https://panel.example.com/api/client
DB_PATH=/data/ec2bot.dbIf you followed "Step 3: Create an EC2 Instance" above, this should already be done. Verify:
# Check your instance has the guild tag
aws ec2 describe-instances \
--region YOUR_REGION \
--filters "Name=tag:guild,Values=YOUR_GUILD_ID" \
--query 'Reservations[*].Instances[*].[InstanceId,State.Name,Tags]'Expected output should show your instance ID with "running" or "stopped" state.
docker-compose up -ddocker-compose logs -f ec2-discord-bot| Command | Description |
|---|---|
.info |
Display EC2 instance status, IP, uptime, and server status |
.ping |
Check bot latency |
.start |
Start the EC2 instance |
.stop |
Stop the EC2 instance and log uptime |
.state |
Check current EC2 instance state |
.totaluptime |
Display total uptime for the current day |
.lrs |
List running servers on the panel |
Understanding the complete interaction flow:
Discord User → Discord Bot (Docker Container) → AWS EC2 API → EC2 Instance
↓
SQLite Database (uptime tracking)
↓
Pterodactyl Panel (optional game server management)
-
User sends command in Discord
User types: .start -
Bot receives message
- Bot is listening to messages in the Discord guild (server)
- Validates the message is from the configured guild ID
- Parses the command (
.start)
-
Bot queries EC2 for tagged instances
instances = ec2.instances.filter( Filters=[{'Name':'tag:guild', 'Values': [guild_id]}] )
- Uses boto3 SDK to connect to AWS EC2 API
- Authenticates using IAM credentials from
.env - Filters instances by the
guildtag matching your Guild ID - Returns list of matching instances (bot uses first one)
-
Bot checks current instance state
current_state = instance.state['Name'] # 'stopped', 'running', etc.
-
Bot sends start command to AWS
instance.start()
- Calls AWS EC2 API:
StartInstances - AWS begins instance startup sequence
- Takes 30-60 seconds for instance to fully start
- Calls AWS EC2 API:
-
Bot monitors and responds
- Sends "Starting EC2 instance..." message to Discord
- Enters hourly countdown loop
- Checks instance state every hour
- Sends status updates to Discord
-
User retrieves instance information
User types: .info Bot responds with: Instance IP, state, uptime, etc.
IAM Policy Enforcement:
- The bot's IAM user can ONLY control instances you specified
- Policy restricts actions to
StartInstances,StopInstances,RebootInstances - Even if someone gains access to the bot, they can't:
- Delete instances
- Create new instances
- Access other AWS resources
- Control instances without the guild tag
Guild ID Filtering:
- Bot only responds to commands from YOUR Discord server
guild_idenvironment variable restricts access- Even if bot is in multiple servers, it only works in one
Tag-Based Instance Selection:
- Bot finds instances using
guildtag - Tag value must exactly match your Discord Guild ID
- No tag = bot won't see the instance
- Wrong tag value = bot won't control it
Uptime Tracking:
- When you
.stopthe instance, bot calculates session duration - Stores uptime in SQLite database:
/data/ec2bot.db - Database persists in Docker volume
.totaluptimecommand queries database for daily totals
Docker Volume:
volumes:
- bot-data:/data # Named volume for persistence- Database survives container restarts
- Data remains even if container is recreated
- Backup-friendly (just copy the volume)
If you're running game servers (Minecraft, etc.) via Pterodactyl panel:
- Bot can query server status via Pterodactyl API
- Shows running servers in
.infocommand - Lists active servers with
.lrscommand - Requires
api,panel_url, andget_server_urlconfiguration
Not using Pterodactyl? The bot works fine without it - just leave default values in .env.
python -m venv env
source env/bin/activate # On Windows: env\Scripts\activatepip install -r requirements.txtFollow steps 2-4 from the Docker setup above.
For local development, change DB_PATH in .env:
DB_PATH=./ec2bot.dbpython bot.pyaws_ec2_discord_controller/
├── api.py # Pterodactyl panel API integration
├── bot.py # Discord bot main file
├── functions.py # Utility functions for EC2 and panel
├── requirements.txt # Python dependencies
├── Dockerfile # Docker container definition
├── docker-compose.yml # Docker Compose configuration
├── .env.example # Example environment variables
├── .gitignore # Git ignore rules
└── README.md # This file
docker-compose up -ddocker-compose downdocker-compose logs -fdocker-compose up -d --builddocker-compose exec ec2-discord-bot sqlite3 /data/ec2bot.dbThe bot uses a named Docker volume (bot-data) to persist the SQLite database across container restarts. The database is stored at /data/ec2bot.db inside the container.
To backup the database:
docker-compose exec ec2-discord-bot cat /data/ec2bot.db > backup.dbTo restore the database:
cat backup.db | docker-compose exec -T ec2-discord-bot tee /data/ec2bot.db > /dev/null.env file to version control. It contains sensitive credentials.
- The
.envfile is already excluded in.gitignore - Rotate all credentials if they are accidentally exposed
- Use IAM roles when running on EC2 instead of hardcoded AWS credentials
- Consider using AWS Secrets Manager or similar for production deployments
- The Docker container runs as a non-root user for security
- Check logs:
docker-compose logs -f - Verify all environment variables in
.envare set correctly - Ensure EC2 instances are tagged with the correct guild ID
- Ensure the
/datavolume is properly mounted - Check file permissions on the database file
- Verify AWS credentials are correctly configured
- Test with:
docker-compose exec ec2-discord-bot aws sts get-caller-identity - Ensure IAM permissions include EC2 read/write access
- Verify the bot token is correct
- Check bot has proper permissions in your Discord server
- Ensure bot is online in Discord
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
See LICENSE file for details.
- Implement server start/stop functions for Pterodactyl integration
- Add Discord UI components (buttons) for commands
- Add command permissions/role checks
- Migrate to discord.py v2.x
- Add unit tests
- Implement proper logging system
- Add support for multiple EC2 instances