Are you still manually deploying FreePBX instances through the AWS console? In 2025, Infrastructure as Code (IaC) has become the standard for deploying and managing cloud resources. This comprehensive guide will show you how to deploy the our Custom FreePBX 17 image on AWS using three popular IaC tools: Terraform, CloudFormation and Ansible.
FreePBX is an open-source, web-based graphical user interface (GUI) that simplifies the management of Asterisk, the world’s most popular open-source communications engine. Designed to make voice-over-IP (VoIP) phone systems accessible and manageable for businesses of all sizes, FreePBX provides a user-friendly interface for configuring and maintaining PBX features like call routing, voicemail, IVRs, conferencing, and call recording. It supports both traditional phone lines and modern SIP-based communication, offering flexibility and scalability. Backed by a large community and supported commercially by Sangoma, FreePBX is widely adopted for building robust, customizable telephony solutions without the need for deep telecom expertise.
Why Infrastructure as Code for FreePBX?
Traditional manual deployment of FreePBX has several limitations:
- No repeatability: Each deployment requires clicking through the same GUI steps
- Prone to human error: Missing a security group rule or forgetting to assign an Elastic IP
- No version control: Can’t track changes or roll back configurations
- Difficult to scale: Deploying multiple instances becomes tedious
- No disaster recovery plan: Recreating infrastructure manually is time-consuming
Infrastructure as Code solves all these problems while adding benefits like:
- Automated deployments in minutes
- Version-controlled infrastructure
- Consistent environments across development, staging, and production
- Easy multi-region deployments
- Built-in documentation through code
Prerequisites
Before we begin, ensure you have:
- An AWS account with appropriate permissions
- Basic knowledge of AWS services (EC2, VPC, Security Groups)
- One of the following tools installed:
- Terraform (v1.5+)
- AWS CLI (for CloudFormation)
- Ansible (v2.9+)
Part 1: Deploying FreePBX with Terraform
Terraform is HashiCorp’s open-source IaC tool that uses a declarative language to define infrastructure.
Complete Terraform Configuration
Create a file named freepbx.tf
:
# Provider configuration
provider "aws" {
region = var.aws_region
}
# Data source for latest FreePBX AMI
data "aws_ami" "freepbx" {
most_recent = true
owners = ["679593333241"] # AWS MarketPlace ID
filter {
name = "name"
values = ["SolveDevOps-FreePBX-17-*"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
}
# Elastic IP
resource "aws_eip" "freepbx" {
domain = "vpc"
tags = {
Name = "FreePBX-EIP"
}
}
# EC2 Instance
resource "aws_instance" "freepbx" {
ami = data.aws_ami.freepbx.id
instance_type = var.instance_type
key_name = var.key_name
#subnet_id = aws_subnet.freepbx_public.id
vpc_security_group_ids = var.security_groups_ids
#associate_public_ip_address = true
root_block_device {
volume_type = "gp3"
volume_size = 60
encrypted = true
}
tags = {
Name = "FreePBX-Server"
}
}
# EIP Association
resource "aws_eip_association" "freepbx" {
instance_id = aws_instance.freepbx.id
allocation_id = aws_eip.freepbx.id
}
# Data source for availability zones
##data "aws_availability_zones" "available" {
# state = "available"
#}
# Outputs
output "freepbx_public_ip" {
value = aws_eip.freepbx.public_ip
}
output "freepbx_admin_url" {
value = "http://${aws_eip.freepbx.public_ip}/admin"
}
output "ssh_connection_string" {
value = "ssh -i ${var.key_name}.pem admin@${aws_eip.freepbx.public_ip}"
}
Terraform Variables File
Create a terraform.tfvars
file:
aws_region = "us-east-1"
instance_type = "t3.large"
key_name = "your-key-pair-name"
allowed_ips = ["YOUR_IP/32"]
Terraform Variables File
Create a vars.tf
file:
# Variables
variable "aws_region" {
description = "AWS region for FreePBX deployment"
default = "us-east-1"
}
variable "instance_type" {
description = "EC2 instance type for FreePBX"
default = "t3.medium"
}
variable "key_name" {
description = "AWS key pair name for SSH access"
type = string
}
variable "security_groups_ids" {
description = "List of Subnet Group Ids"
type = list(string)
default = []
}
Deploying with Terraform
# Initialize Terraform
terraform init
# Review the execution plan
terraform plan
# Deploy FreePBX
terraform apply
At the end of your apply, your will end up with output like below
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
freepbx_admin_url = "http://1.2.3.4/admin"
freepbx_public_ip = "1.2.3.4"
ssh_connection_string = "ssh -i key.pem admin@1.2.3.4"
Part 2: Deploying FreePBX with CloudFormation
CloudFormation is AWS’s native IaC service that uses JSON or YAML templates.
Complete CloudFormation Template
Create a file named freepbx-stack.yaml
:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'FreePBX 17 deployment using AWS MarketPlace Image'
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: Must be the name of an existing EC2 KeyPair
InstanceType:
Description: EC2 instance type for FreePBX
Type: String
Default: t3.large
AllowedValues:
- t3.large
- t3.xlarge
ConstraintDescription: Must be a valid EC2 instance type
Mappings:
RegionMap:
ap-south-1:
AMI: ami-03e979d5acfc44589
eu-north-1:
AMI: ami-0c5089f6bb0d107d3
eu-west-3:
AMI: ami-0e8e360c164d9185c
eu-west-2:
AMI: ami-0777b154b363e0475
eu-west-1:
AMI: ami-08e969b26353741b4
ap-northeast-3:
AMI: ami-06c5350dff9c782a4
ap-northeast-2:
AMI: ami-00b1e77cd16d3a563
ap-northeast-1:
AMI: ami-01aaf195d29079f0b
ca-central-1:
AMI: ami-03a902cbcb219a98f
sa-east-1:
AMI: ami-04618d8dc8eb711a5
ap-southeast-1:
AMI: ami-0190701d77134dfc6
ap-southeast-2:
AMI: ami-0dc40428cb05523a3
eu-central-1:
MI: ami-083e759382c1b4751
us-east-1:
AMI: ami-055f22fdd66a5d37b
us-east-2:
AMI: ami-0f99bdd88c2ef5629
us-west-1:
AMI: ami-06404e2d1c3fdbfab
us-west-2:
AMI: ami-03739ba43e9d8abe9
Resources:
# Elastic IP
FreePBXEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: FreePBX-EIP
# EC2 Instance
FreePBXInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', AMI]
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
SecurityGroupIds:
- sg-01234567890987654
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 60
Encrypted: true
Tags:
- Key: Name
Value: FreePBX-Server
# EIP Association
EIPAssociation:
Type: AWS::EC2::EIPAssociation
Properties:
InstanceId: !Ref FreePBXInstance
EIP: !Ref FreePBXEIP
Outputs:
PublicIP:
Description: Public IP address of FreePBX instance
Value: !Ref FreePBXEIP
AdminURL:
Description: FreePBX Admin URL
Value: !Sub 'http://${FreePBXEIP}/admin'
SSHConnection:
Description: SSH connection string
Value: !Sub 'ssh -i ${KeyName}.pem admin@${FreePBXEIP}'
Deploying with CloudFormation
aws cloudformation create-stack \
--stack-name freepbx-stack \
--template-body file://freepbx-stack.yaml \
--parameters \
ParameterKey=KeyName,ParameterValue=my_key \
ParameterKey=InstanceType,ParameterValue=t3.large
Check stack system
# Check stack status
aws cloudformation describe-stacks --stack-name freepbx-stack
Check stack on AWS Cloudformation stack status

Part 3: Deploying FreePBX with Ansible
Ansible uses playbooks to define automation tasks. This approach combines infrastructure provisioning with configuration management.
Project Structure
freepbx-ansible/
├── playbook.yml
├── inventory.ini
├── group_vars/
│ └── all.yml
└── roles/
└── freepbx/
├── tasks/
│ └── main.yml
├── templates/
│ └── sip_settings.j2
└── vars/
└── main.yml
Main Playbook
Create playbook.yml
:
---
- name: Deploy FreePBX on AWS
hosts: localhost
connection: local
gather_facts: false
vars:
aws_region: us-east-1
instance_type: t3.large
key_name: "solve-useast1"
ami_id: "ami-055f22fdd66a5d37b" # FreePBX image
tasks:
- name: Allocate Elastic IP
amazon.aws.ec2_eip:
region: "{{ aws_region }}"
in_vpc: yes
register: eip
- name: Launch FreePBX Instance
amazon.aws.ec2_instance:
key_name: "{{ key_name }}"
instance_type: "{{ instance_type }}"
image_id: "{{ ami_id }}"
wait: yes
region: "{{ aws_region }}"
security_group: "sg-12345678909876543"
volumes:
- device_name: /dev/xvda
ebs:
volume_type: gp3
volume_size: 60
encrypted: yes
tags:
Name: FreePBX-Server
register: ec2
- name: Associate Elastic IP
amazon.aws.ec2_eip:
device_id: "{{ ec2.instances[0].instance_id }}"
ip: "{{ eip.public_ip }}"
region: "{{ aws_region }}"
- name: Add host to inventory
add_host:
hostname: "{{ eip.public_ip }}"
groups: freepbx
ansible_user: admin
ansible_ssh_private_key_file: "{{ key_name }}.pem"
Running the Ansible Playbook
# Install required collections
ansible-galaxy collection install amazon.aws
# Run the playbook
ansible-playbook playbook.yml
Advanced Configurations
1. Multi-AZ High Availability
For production deployments, consider implementing:
- Active-passive failover with database replication
- Shared storage using EFS for recordings
- Route 53 health checks for automatic failover
2. Auto-Scaling for Call Centers
Implement auto-scaling based on:
- Concurrent call metrics from CloudWatch
- CPU utilization thresholds
- Custom metrics from Asterisk AMI
3. Backup Automation
Add automated backups:
- Daily EBS snapshots
- FreePBX configuration backups to S3
- Call recordings archival to Glacier
4. Monitoring and Alerting
Integrate monitoring:
- CloudWatch metrics for system health
- SNS notifications for critical events
- Custom dashboards for call statistics
Security Best Practices
- Restrict Security Groups: Never use 0.0.0.0/0 for SSH access in production
- Enable Fail2ban: Configure FreePBX’s built-in intrusion detection
- Use SSL/TLS: Enable HTTPS and secure SIP (TLS/SRTP)
- Regular Updates: Automate security patches with Systems Manager
- IAM Roles: Use instance profiles instead of access keys
- Encryption: Enable EBS encryption and S3 bucket encryption
Cost Optimization
- Right-sizing: Start with t3.large and monitor usage
- Reserved Instances: Save up to 72% for production workloads
- Spot Instances: Use for development/testing environments
- Storage Optimization: Use lifecycle policies for call recordings
Troubleshooting Common Issues
Issue 1: Cannot Access Web Interface
sudo systemctl status freepbx
sudo systemctl status apache2
# Check firewall rules or security group firewalls
sudo iptables -L -n
Issue 2: No Audio on Calls
See this article.
Issue 3: High CPU Usage
# Monitor Asterisk processes
htop
asterisk -rx 'core show channels'
Conclusion
Infrastructure as Code transforms FreePBX deployment from a manual, error-prone process into a repeatable, version-controlled operation. Whether you choose Terraform for its cloud-agnostic approach, CloudFormation for native AWS integration, or Ansible for its configuration management capabilities, you now have the tools to deploy FreePBX professionally.
The Solve DevOps FreePBX image combined with these IaC approaches provides:
- 5-minute deployments instead of hours
- Consistent environments across all stages
- Disaster recovery capabilities
- Cost optimization through automation
- Security best practices built-in
Start with the tool that best fits your existing workflow and gradually expand to implement advanced features like high availability and auto-scaling.
Next Steps
- Choose your preferred IaC tool and deploy a test environment
- Customize the templates for your specific requirements
- Implement monitoring and backup strategies
- Document your deployment process
- Share your improvements with the community
Did You Just Read Gibberish?
Our Tech Support Staff understand gibberish and would love to work with you. Your business needs you, lets take care of the backend stuff.
Gibberish Helpline