Skip to content

Discourse on AWS: Elastic Beanstalk + RDS + S3 + SES + Lambda + Terraform

License

Notifications You must be signed in to change notification settings

ento/discourse_aws

Repository files navigation

Tooling to deploy Discourse on AWS.

what's where

  • Postgres: RDS
  • Rails + Redis: Docker container on Elastic Beanstalk Single Instance deployment
  • Docker registry: ECR
  • Files and backups: S3
  • Outgoing email: SES
  • Incoming email + bounce handling: SES + S3 + AWS Lambda
  • Passwords for RDS and SES: credstash
  • SSL: Let's Encrypt + nginx on the EC2 instance managed by Elastic Beanstalk
  • Infrastructure management: Terraform

what's different from the official launcher

  • Skips db:migrate and assets:precompile on bootstrap
  • Uses a custom boot script to:
    • Fetch passwords and export as environment variables
    • Run db:migrate and assets:precompie
    • Execute the original boot script

hardcoded assumptions

  • We will have one Elastic Beanstalk application named discourse
  • and two Elastic Beanstalk environments: discourse-dev and discourse-prod

directory layout

path/to/your/configs
  discourse_aws/ # this repo
  containers/app.yml           # optional pups template to customize the Docker build
  ebextensions/                # optional Elastic Beanstalk configs
  dev/*.tf                     # mix and match modules from discourse_aws/tfmodules..
  prod/*.tf                    # to build AWS resources according to your needs.
  • discourse_aws/
    • bring in this repo in whatever way you like: git submodule, git subtree, or a plain git clone
  • ./containers/app.yml
    • this file, if present, will be merged with this repo's ./containers/app.yml
    • useful for configuring plugins to install (see: ./samples/app.yml)
  • ./ebextensions/*.config
    • any file in here will be copied to the sourcebundle for Elastic Beanstalk
    • useful for setting up SSH keys on the EC2 instance (see: ./samples/ssl.config)

prerequisites

  • install Terraform
  • set up credstash
  • set up your domain name of choice
    • CNAME -> cname_prefix.your_aws_region.elasticbeanstalk.com
    • MX -> inbound-smtp.your_ses_region.amazonaws.com
  • set up SES
    • make a new SES user/password
    • verify your sender domain or email address
    • make a receipt rule set and make it active
    • request production access (this can be done later)

dev setup

  • write your own Terraform config by combining modules in ./tfmodules (see: ./samples/main.tf)
    • consider setting certbot_extra_args to --staging first to test SSL setup
  • plug in Terraform variables
    • domain name
    • etc
  • initial deploy strategy should be AllAtOnce
    • plus whenever you expect certbot to create a new certificate
  • terraform apply
  • change db password on RDS
  • credstash put discourse_db_password.discourse-dev
  • credstash put discourse_smtp_password.discourse-dev
  • credstash put discourse_smtp_username.discourse-dev
  • ./build.sh
    • builds and tags a Discourse docker image as vYYYYmmdd-HHMMSS
  • do a docker push: exact command will be printed out by build.sh
  • ./deploy-dev.sh
    • creates and deploys an application version using the latest docker image on ECR: vYYYYmmdd-HHMMSS-bYYYYmmdd-HHMMSS
  • change deploy strategy to Immutable to avoid downtime during deploys

prod setup

same as dev setup except for:

  • credstash put discourse_db_password.discourse-prod
  • credstash put discourse_smtp_password.discourse-prod
  • credstash put discourse_smtp_username.discourse-prod
  • deploy script is ./deploy-prod.sh
    • deploys the same application version as discourse-dev environment's

community setup

  • setup s3 upload (otherwise your uploads will be wiped after the next deploy)
  • setup s3 backup (optional)
  • set up incoming email (advisable - to meet SES's bounce handling guidelines)
    • generate a master API key under Admin > API, go to the Lambda function for receiving email, and set the API key as DISCOURSE_API_KEY enivonment variable
    • site setup
      • manual polling enabled
      • reply by email address
      • reply by email enabled
    • test email receiver by sending a test email to one of the test email addresses at http://docs.aws.amazon.com/ses/latest/DeveloperGuide/mailbox-simulator.html
  • go through the setup wizard

getting ready for let's encrypt production server

  • ssh into the instance
  • delete staging certs sudo find /etc/letsencrypt -iname "$your_discourse_hostname*" | xargs rm -rf
  • also delete on s3
  • remove --staging from certbot_extra_args. empty string is okay
  • redeploy through Elastic Beanstalk console or another ./deploy-dev.sh / ./deploy-prod.sh

upgrading / adding plugins

  • optional: update your ./containers/app.yml
  • ./build.sh: builds a docker image locally
  • docker push: as instructed at the end of ./build.sh's output
  • ./deploy-dev.sh: packages up a new application version and deploys to discourse-dev
  • ./deploy-prod.sh: deploys the current application version deployed to discourse-dev

cycling SMTP credentials

SMTP credentials is tied to the AWS access key of the user you created.

  • Create a new key pair for the existing user
  • Update the dev environment
    • Update the SMTP credentials: credstash put discourse_smtp_password.discourse-dev credstash put discourse_smtp_username.discourse-dev
    • Restart app servers of the dev environment through Elastic Beanstalk's console
    • Send a test email through https://<your dev discourse domain>/admin/email
  • Update the prod environment
    • Update the SMTP credentials: credstash put discourse_smtp_password.discourse-prod credstash put discourse_smtp_username.discourse-prod
    • Restart app servers of the prod environment through Elastic Beanstalk's console
    • Send a test email through https://<your prod discourse domain>/admin/email
  • Delete the old AWS access key once the new key's last used time is updated in the IAM console