AWSTemplateFormatVersion: 2010-09-09 Description: >- concerto-ec2-basic-tls (2020-09-02): Standalone Concerto, everything on one instance Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Concerto Parameters: - ConcertoVersion - ConcertoPassword - ConcertoContentURL - ConcertoSessionLimit - ConcertoTimezone - ConcertoStorage - Label: default: Web Parameters: - DomainName - Email - KeyName - WebServerInstanceType - Label: default: Database Parameters: - DBPassword - Label: default: Network Parameters: - CIDR - CIDRA ParameterLabels: ConcertoVersion: default: Tag ConcertoPassword: default: Password ConcertoContentURL: default: URL ConcertoSessionLimit: default: Session limit ConcertoTimezone: default: Timezone ConcertoStorage: default: Storage DomainName: default: Domain Email: default: E-Mail KeyName: default: Key pair WebServerInstanceType: default: Instance type DBPassword: default: Password CIDRA: default: CIDR for Subnet A Parameters: ConcertoVersion: Description: Concerto version to use. Can be any tag from https://github.com/campsych/concerto-platform Type: String Default: 5.0 ConcertoPassword: Description: Concerto admin account password (recommended to generate a random one) Type: String NoEcho: true MinLength: 8 ConstraintDescription: min. 8 characters. ConcertoContentURL: Description: URL with Concerto content backup to preload (defaults to starter content) Type: String Default: . ConcertoSessionLimit: Description: How many concurrent sessions to allow (unlimited if 0 or not set) Type: Number Default: 0 ConcertoTimezone: Description: Timezone to use, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones Type: String Default: UTC ConcertoStorage: Default: 8 Description: The size of the storage volume (Gb) Type: Number MinValue: 8 MaxValue: 1024 ConstraintDescription: must be between 8 and 1024Gb DomainName: Description: The domain name to be used for Concerto, you need to own it Type: String AllowedPattern: (?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9] ConstraintDescription: must be a valid domain name Email: Description: Your email to be used with Lets Encrypt CA Type: String AllowedPattern: ([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?) ConstraintDescription: must be a valid email KeyName: Description: Name of an existing EC2 KeyPair to enable SSH access to the instance Type: AWS::EC2::KeyPair::KeyName ConstraintDescription: must be the name of an existing EC2 KeyPair WebServerInstanceType: Description: Web server instance type Type: String Default: t2.micro AllowedValues: - t2.micro - t3.micro - t2.small - t3.small - t2.medium - t3.medium - t2.large - t3.large ConstraintDescription: must be a valid EC2 instance type DBPassword: Description: Database admin account password (recommended to generate a random one, different than Concerto's) Type: String NoEcho: true MinLength: 8 ConstraintDescription: min. 8 characters CIDR: Description: The private IP address range to be used for VPC Type: String MinLength: 9 MaxLength: 18 Default: 10.10.0.0/16 AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x CIDRA: Description: Address range within the VPC to be used for the subnet Type: String MinLength: 9 MaxLength: 18 Default: 10.10.0.0/24 AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x Mappings: RegionMap: us-east-1: ami: ami-0b898040803850657 us-east-2: ami: ami-0d8f6eb4f641ef691 us-west-1: ami: ami-056ee704806822732 us-west-2: ami: ami-082b5a644766e0e6f eu-west-1: ami: ami-0bbc25e23a7640b9b eu-west-2: ami: ami-0d8e27447ec2c8410 eu-west-3: ami: ami-0adcddd3324248c4c eu-central-1: ami: ami-0cc293023f983ed53 eu-north-1: ami: ami-3f36be41 ap-east-1: ami: ami-570c7726 ap-northeast-1: ami: ami-0c3fd0f5d33134a76 ap-northeast-2: ami: ami-095ca789e0549777d ap-southeast-1: ami: ami-01f7527546b557442 ap-southeast-2: ami: ami-0dc96254d5535925f ap-south-1: ami: ami-0d2692b6acea72ee6 ca-central-1: ami: ami-0d4ae09ec9361d8ac sa-east-1: ami: ami-058943e7d9b9cabfb InstanceTypeMap: t2.micro: MaxChildren: 5 t3.micro: MaxChildren: 5 t2.small: MaxChildren: 20 t3.small: MaxChildren: 20 t2.medium: MaxChildren: 50 t3.medium: MaxChildren: 50 t2.large: MaxChildren: 100 t3.large: MaxChildren: 100 Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref CIDR Tags: - Key: Name Value: !Ref AWS::StackName SubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Ref CIDRA Tags: - Key: Name Value: !Ref AWS::StackName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref AWS::StackName AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Ref AWS::StackName Route: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref SubnetA RouteTableId: !Ref RouteTable NetworkAcl: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Ref AWS::StackName InboundHTTPNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 100 Protocol: 6 RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PortRange: From: 80 To: 80 InboundHTTPSNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 101 Protocol: 6 RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PortRange: From: 443 To: 443 InboundSSHNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 102 Protocol: 6 RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PortRange: From: 22 To: 22 InboundResponsePortsNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 103 Protocol: 6 RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PortRange: From: 1024 To: 65535 OutBoundHTTPNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 100 Protocol: 6 RuleAction: allow Egress: true CidrBlock: 0.0.0.0/0 PortRange: From: 80 To: 80 OutBoundHTTPSNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 101 Protocol: 6 RuleAction: allow Egress: true CidrBlock: 0.0.0.0/0 PortRange: From: 443 To: 443 OutBoundResponsePortsNetworkAclEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref NetworkAcl RuleNumber: 102 Protocol: 6 RuleAction: allow Egress: true CidrBlock: 0.0.0.0/0 PortRange: From: 1024 To: 65535 SubnetNetworkAclAssociation: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref SubnetA NetworkAclId: !Ref NetworkAcl WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VPC GroupDescription: Allow ingress via SSH, HTTP, HTTPS ports SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: !Ref AWS::StackName WebServerInstance: Type: AWS::EC2::Instance CreationPolicy: ResourceSignal: Count: 1 Timeout: PT15M Metadata: AWS::CloudFormation::Init: configSets: default: - cfn - updates - docker - tls - concerto cfn: files: /etc/cfn/cfn-hup.conf: content: !Sub | [main] stack=${AWS::StackId} region=${AWS::Region} interval=1 mode: 000400 owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Sub | [cfn-auto-reloader-hook] triggers=post.update path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} runas=root mode: 000400 owner: root group: root services: sysvinit: cfn-hup: enabled: true ensureRunning: true files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf updates: packages: yum: yum-cron: [] commands: 01_config: command: | sed -ri 's/^(.*update_cmd\s*=).*$/\1 security/' yum-cron.conf sed -ri 's/^(.*apply_updates\s*=).*$/\1 yes/' yum-cron.conf cwd: /etc/yum services: sysvinit: yum-cron: enabled: true ensureRunning: true docker: commands: 01_user: command: usermod -a -G docker ec2-user 02_docker_compose: command: | curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Linux-x86_64 -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose services: sysvinit: docker: enabled: true ensureRunning: true tls: files: /home/concerto/data/certbot/conf/cert.pem: content: | -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1 WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf 89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2 DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1 eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY 2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0 ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc6bLEeMfizANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDEwMloXDTIxMDMxNzE2NDEwMlow SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFg0MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4SR0Qnu3kTHZc/84qtjORFy3OQrcRK4NvUW5lzdnr71QT1/T EFRr90HajmPmbVvA6ECpjEH80QOJ/2JhCWDWBwV4mpC9GmQ+T9zPdy+Ja8tnr0FN xY0AwGv+jYTctfKVMajo9pCgQ0qTdFyzPkNpS4kiR3RRPplkw80kAfmELyh3FyKn 3cNsCExmLzd0xW+TjrBGNxZh0VCYyLAPT1hTfKz22i2WYVCtQ9wKpk+etVK5nI7v Tt9GszHcIPxpwqMgdT7sOBs2TmZm0t/1ZqSTL3umDpQ+YD1KSxxvurRNHDyRWG4v TcTacNvtATl2wEnn6TW1FAaQweWS4hD9a7m0hQIDAQABo4IBfTCCAXkwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu Y3JsMB0GA1UdDgQWBBTFsatOTLHNZDCTfsGEmQWr5gPiJTANBgkqhkiG9w0BAQsF AAOCAQEANlaeSdstfAtqFN3jdRZJFjx9X+Ob3PIDlekPYQ1OQ1Uw43rE1FUj7hUw g2MJKfs9b7M0WoQg7C20nJY/ajsg7pWhUG3J6rlkDTfVY9faeWi0qsPYXE6BpBDr 5BrW/Xv8yT8U2BiEAmNggWq8dmFl82fghmLzHBM8X8NZ3ZwA1fGePA53AP5IoD+0 ArpW8Ik1sSuQBjZ8oQLfN+G8OoY7MNRopyLyQQCNy4aWfE+xYnoVoa5+yr+aPiX0 7YQrY/cKawAn7QB4PyF5//IKSAVs7mAuB68wbMdE3FKfOHfJ24W4z/bIJTrTY8Y5 Sr4AUhtzf8oVDrHZYWRrP4joIcOu/Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIRAJObmZ6kjhYNW0JZtD0gE9owDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0NDM0 WhcNMjExMDA2MTU0NDM0WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDQwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhJHRCe7eRMdlz/ziq2M5EXLc5 CtxErg29RbmXN2evvVBPX9MQVGv3QdqOY+ZtW8DoQKmMQfzRA4n/YmEJYNYHBXia kL0aZD5P3M93L4lry2evQU3FjQDAa/6NhNy18pUxqOj2kKBDSpN0XLM+Q2lLiSJH dFE+mWTDzSQB+YQvKHcXIqfdw2wITGYvN3TFb5OOsEY3FmHRUJjIsA9PWFN8rPba LZZhUK1D3AqmT561Urmcju9O30azMdwg/GnCoyB1Puw4GzZOZmbS3/VmpJMve6YO lD5gPUpLHG+6tE0cPJFYbi9NxNpw2+0BOXbASefpNbUUBpDB5ZLiEP1rubSFAgMB AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBTF satOTLHNZDCTfsGEmQWr5gPiJTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB AF4tI1yGjZgld9lP01+zftU3aSV0un0d2GKUMO7GxvwTLWAKQz/eT+u3J4+GvpD+ BMfopIxkJcDCzMChjjZtZZwJpIY7BatVrO6OkEmaRNITtbZ/hCwNkUnbk3C7EG3O GJZlo9b2wzA8v9WBsPzHpTvLfOr+dS57LLPZBhp3ArHaLbdk33lIONRPt9sseDEk mdHnVmGmBRf4+J0Wy67mddOvz5rHH8uzY94raOayf20gzzcmqmot4hPXtDG4Y49M oFMMT2kcWck3EOTAH6QiGWkGJ7cxMfSL3S0niA6wgFJtfETETOZu8AVDgENgCJ3D S0bz/dhVKvs3WRkaKuuR/W0nnC2VDdaFj4+CRF8LGtn/8ERaH48TktH5BDyDVcF9 zfJ75Scxcy23jAL2N6w3n/t3nnqoXt9Im4FprDr+mP1g2Z6Lf2YA0jE3kZalgZ6l NHu4CmvJYoOTSJw9X2qlGl1K+B4U327rG1tRxgjM76pN6lIS02PMECoyKJigpOSB u4V8+LVaUMezCJH9Qf4EKeZTHddQ1t96zvNd2s9ewSKx/DblXbKsBDzIdHJ+qi6+ F9DIVM5/ICdtDdulOO+dr/BXB+pBZ3uVxjRANvJKKpdxkePyluITSNZHbanWRN07 gMvwBWOL060i4VrL9er1sBQrRjU9iNpZQGTnLVAxQVFu -----END CERTIFICATE----- /home/concerto/data/nginx/app.conf: content: !Sub | server { listen [::]:80 default_server; listen 80 default_server; server_tokens off; location /.well-known/acme-challenge/ { root /var/www/certbot; allow all; } location / { return 301 https://$host$request_uri; } } server { listen [::]:443 ssl http2 default_server; listen 443 ssl http2 default_server; server_tokens off; ssl_certificate /etc/letsencrypt/dummy/${DomainName}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/dummy/${DomainName}/privkey.pem; ssl_dhparam /etc/letsencrypt/dhparam.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/letsencrypt/cert.pem; add_header Strict-Transport-Security max-age=15768000 always; client_max_body_size 50M; location / { proxy_pass http://concerto; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_hide_header X-Powered-By; } } commands: 01_mkdir: command: !Sub mkdir -p /home/concerto/data/certbot/conf/dummy/${DomainName} 02_dhparam: command: >- if [[ ! -e dhparam.pem ]]; then openssl dhparam -out dhparam.pem 2048; fi cwd: /home/concerto/data/certbot/conf 03_dummy_certs: command: !Sub >- if [[ ! -e fullchain.pem ]]; then openssl req -x509 -nodes -newkey rsa:4096 -days 7 -keyout privkey.pem -out fullchain.pem -subj '/CN=${DomainName}'; fi cwd: !Sub /home/concerto/data/certbot/conf/dummy/${DomainName} concerto: files: /home/concerto/docker-compose.yml: content: !Sub - | version: '3' services: database: image: mysql:5.7 container_name: database restart: unless-stopped volumes: - ./data/mysql:/var/lib/mysql environment: - MYSQL_DATABASE=concerto - MYSQL_USER=concerto - MYSQL_PASSWORD=${DBPassword} - MYSQL_ROOT_PASSWORD=${DBPassword} - TZ=${ConcertoTimezone} concerto: image: campsych/concerto-platform:${ConcertoVersion} container_name: concerto restart: unless-stopped volumes: - ./data/concerto:/data environment: - CONCERTO_PASSWORD=${ConcertoPassword} - CONCERTO_CONTENT_URL=${ConcertoContentURL} - CONCERTO_PLATFORM_URL=/ - CONCERTO_GIT_REPOSITORY_PATH=/data/git - CONCERTO_SESSION_LIMIT=${ConcertoSessionLimit} - DB_HOST=database - DB_PASSWORD=${DBPassword} - PHP_FPM_PM=static - PHP_FPM_PM_MAX_CHILDREN=${MaxChildren} - TZ=${ConcertoTimezone} nginx: image: nginx container_name: nginx restart: unless-stopped volumes: - ./data/nginx:/etc/nginx/conf.d - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot ports: - "80:80" - "443:443" command: "/bin/sh -c 'trap exit TERM; while :; do if $$(find /etc/letsencrypt/live/${DomainName}/fullchain.pem -mmin -20); then sed -i s/dummy/live/g /etc/nginx/conf.d/app.conf; nginx -s reload; fi; sleep 15m & wait $${!!}; done & nginx -g \"daemon off;\"'" certbot: image: certbot/certbot container_name: certbot restart: unless-stopped volumes: - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot certonly --non-interactive --webroot -w /var/www/certbot --email ${Email} -d ${DomainName} --agree-tos || true; sleep 15m & wait $${!!}; done;'" - MaxChildren: !FindInMap - InstanceTypeMap - !Ref WebServerInstanceType - MaxChildren commands: start: command: /usr/local/bin/docker-compose up -d --remove-orphans --force-recreate cwd: /home/concerto Properties: ImageId: !FindInMap - RegionMap - !Ref AWS::Region - ami InstanceType: !Ref WebServerInstanceType KeyName: !Ref KeyName UserData: Fn::Base64: !Sub | #!/usr/bin/env bash yum update --security -y yum update aws-cfn-bootstrap -y amazon-linux-extras install -y docker /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource WebServerInstance --region ${AWS::Region} /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WebServerInstance --region ${AWS::Region} BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: DeleteOnTermination: false VolumeSize: !Ref ConcertoStorage NetworkInterfaces: - AssociatePublicIpAddress: true DeleteOnTermination: true DeviceIndex: 0 SubnetId: !Ref SubnetA GroupSet: - !Ref WebServerSecurityGroup Tags: - Key: Name Value: !Ref AWS::StackName Outputs: URL: Value: !Sub https://${DomainName}/admin Description: Concerto administration panel URL ServerIP: Value: !GetAtt WebServerInstance.PublicIp Description: IP address to point your domain to (i.e. with A record) ConcertoVersion: Value: !Ref ConcertoVersion Description: Concerto version being used ConcertoPassword: Value: !Ref ConcertoPassword Description: Concerto admin password DBPassword: Value: !Ref DBPassword Description: Database password