diff --git a/.gitignore b/.gitignore index f3cdb1bc..9c2e87c5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ tools/__pycache__/ externals/ .env .vagrant +**/terraform.tfvars +**/terraform.tfstate* diff --git a/README.md b/README.md index 81d8952d..6868f20e 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Installation See the [setup guide](https://mailinabox.email/guide.html) for detailed, user-friendly instructions. +See the [terraform setup](terraform/README.md) for a mostly automated setup using Amazon Web Services and Terraform. + For experts, start with a completely fresh (really, I mean it) Ubuntu 14.04 LTS 64-bit machine. On the machine... Clone this repository: diff --git a/terraform/README.md b/terraform/README.md new file mode 100644 index 00000000..883de0e6 --- /dev/null +++ b/terraform/README.md @@ -0,0 +1,24 @@ +# Automatic installation in AWS using terraform + +Assuming you have an Amazon Web Services account and you've registered your domain [through their registrar](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-register.html), you can use terraform to automatically create a mailinabox, complete with an EBS-backed volume to take advantage of immutable infrastructure. + +First, [install terraform](https://www.terraform.io/intro/getting-started/install.html). Then, create a new file in this folder titled `terraform.tfvars` with the following information: + +``` +access_key = "" +secret_key = "" +region = "us-east-1" +domain_name = "" +email_address = "" +email_password = "" +``` + +Next, create an ssh keypair associated with the miab. + +``` +ssh-keygen -f ~/.ssh/miab +aws ec2 import-key-pair --key-name miab-key \ + --public-key-material file://$HOME//.ssh/miab.pub +``` + +Then, type in `terraform apply` and wait about 15 minutes. Then, follow the [remaining instructions here](https://mailinabox.email/guide.html#admin) to set up the SSL certificates. diff --git a/terraform/dns.tf b/terraform/dns.tf new file mode 100644 index 00000000..3b6dfe4c --- /dev/null +++ b/terraform/dns.tf @@ -0,0 +1,20 @@ +# Create a record +resource "aws_route53_zone" "main" { + name = "${var.domain_name}" +} + +resource "aws_route53_record" "root_record" { + zone_id = "${aws_route53_zone.main.zone_id}" + name = "" + type = "A" + ttl = 300 + records = ["${aws_instance.web.public_ip}"] +} + +resource "aws_route53_record" "www" { + zone_id = "${aws_route53_zone.main.zone_id}" + name = "www" + type = "A" + ttl = 300 + records = ["${aws_instance.web.public_ip}"] +} diff --git a/terraform/networking.tf b/terraform/networking.tf new file mode 100644 index 00000000..cec6654a --- /dev/null +++ b/terraform/networking.tf @@ -0,0 +1,95 @@ +resource "aws_vpc" "main" { + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = "True" +} + +resource "aws_subnet" "public_subnet_1" { + vpc_id = "${aws_vpc.main.id}" + availability_zone = "us-east-1a" + cidr_block = "10.0.1.0/26" +} + +resource "aws_internet_gateway" "main_gw" { + vpc_id = "${aws_vpc.main.id}" +} + +resource "aws_route_table" "main_route_table" { + vpc_id = "${aws_vpc.main.id}" + route { + cidr_block = "0.0.0.0/0" + gateway_id = "${aws_internet_gateway.main_gw.id}" + } +} + +resource "aws_route_table_association" "route_subnet_1" { + subnet_id = "${aws_subnet.public_subnet_1.id}" + route_table_id = "${aws_route_table.main_route_table.id}" +} + +resource "aws_security_group" "main_sg" { + vpc_id = "${aws_vpc.main.id}" + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # SMTP + ingress { + from_port = 25 + to_port = 25 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 587 + to_port = 587 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 993 + to_port = 993 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 4190 + to_port = 4190 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 53 + to_port = 53 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} diff --git a/terraform/server.tf b/terraform/server.tf new file mode 100644 index 00000000..dcf7bb6b --- /dev/null +++ b/terraform/server.tf @@ -0,0 +1,51 @@ +provider "aws" { + access_key = "${var.access_key}" + secret_key = "${var.secret_key}" + region = "${var.region}" +} + +resource "aws_ebs_volume" "miab_volume" { + availability_zone = "${var.availability_zone}" + size = 40 + tags { + Name = "Mailinabox" + } + encrypted = true +} + + +resource "aws_volume_attachment" "ebs_att" { + device_name = "/dev/sdh" + volume_id = "${aws_ebs_volume.miab_volume.id}" + instance_id = "${aws_instance.web.id}" +} + +resource "aws_instance" "web" { + ami = "ami-0927dc1f" + + # for 16.04 + # ami = "ami-f0768de6" + + instance_type = "t2.micro" + + subnet_id = "${aws_subnet.public_subnet_1.id}" + associate_public_ip_address = true + vpc_security_group_ids = ["${aws_security_group.main_sg.id}"] + key_name = "miab-key" + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "ubuntu" + key_name = "miab-key" + } + inline = [ + "sudo apt-get update && curl -s https://mailinabox.email/setup.sh | sudo env NONINTERACTIVE=1 PRIMARY_HOSTNAME=${var.domain_name} PUBLIC_IP=${aws_instance.web.public_ip} PRIVATE_IP=${aws_instance.web.private_ip} STORAGE_USER=ubuntu STORAGE_ROOT=/home/ubuntu EMAIL_ADDR=${var.email_address} EMAIL_PW=${var.email_password} bash" + ] + } + +} + +output "public_ip_address" { + value = "${aws_instance.web.public_ip}" +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 00000000..c2619e19 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,11 @@ +variable "access_key" {} +variable "secret_key" {} +variable "region" { + default = "us-east-1" +} +variable "availability_zone" { + default = "us-east-1a" +} +variable "domain_name" {} +variable "email_address" {} +variable "email_password" {}