AWS EC2 with Terraform
Serverpod makes it easy to deploy your server to AWS using Github and Terraform. Terraform will set up and manage your infrastructure while you use Github actions to manage versions and deployments. Creating your project using
serverpod create Serverpod will automatically generate your deployment scripts. The default setup uses a minimal configuration that will fit within the AWS free tier, but you can easily modify the configuration to suit your needs.
Using Serverpod’s AWS deployment may incur costs to your AWS account. Serverpod’s scripts are provided as-is, and we take no responsibility for any unexpected charges for using them.
To use the deployment scripts, you will need the following:
- An AWS account. It may take up to 24 hours to get your AWS account up and running.
- AWS CLI, configured with your credentials. Install AWS CLI
- Terraform. Install Terraform
- Your Serverpod project version controlled on Github.
If you haven’t used Terraform before, it’s a great idea to go through their tutorial for AWS, as it will give you a basic understanding of how everything fits together. Get started with Terraform and AWS
The top directory created by Serverpod must be the root directory of your Git repository. Otherwise, the deployment scripts won’t work correctly.
What will be deployed?
The deployment scripts will set up everything you need to run your Serverpod, including an autoscaling cluster of servers, load balancers, a Postgres database, Redis, S3 buckets for file uploads, CloudFront, CodeDeploy, DNS records, and SSL certificates. Some of the components are optional, and you will need to opt in. You can also create a second server cluster for a staging environment. The staging servers allow you to test code before you deploy it to the production servers.
You deploy your configuration with a domain name; the scripts will set up subdomains that provide access to different functions of your deployment:
- api.examplepod.com: This is the entry point for your main Serverpod server.
- app.examplepod.com: The Serverpod web server. If you prefer to host it on your top domain and use www as a redirect, you can change this in the main Terraform configuration file.
- insights.examplepod.com: Provides access to the Serverpod UI and gets insights from your server while it is running.
- database.examplepod.com: This is how you access your database from outside the server.
- storage.examplepod.com: Access to public storage used by Serverpod.
Set up your domain name and certificates
Before deploying your server, you must configure your server’s top domain in AWS. You can register your domain through any registrar, but you need to set up a public hosted zone in Route 53 in AWS.
- Sign in to the AWS console and navigate to Route 53 > Hosted zones.
- Click Create hosted zone.
- Enter your domain name and click Create hosted zone.
- The console will display a number of DNS names for Amazon’s name servers. You will need to have your domain registrar point to these name servers. Depending on your registrar, this process will be slightly different.
- Expand the Hosted zone details and take note of your Hosted zone ID (you will need it in your Terraform configuration later).
Finding the domain name servers for your hosted zone.
Next, you need to create two SSL certificates for your domain. Navigate to AWS Certificate Manager. Here it’s important in which regions you create your certificates. We are deploying to Oregon (us-west-2) in this example, but you can deploy to any region.
- In the top-right corner, choose your preferred region, then click the Request button to request a new certificate.
- Choose to request a public certificate.
- For the Fully qualified domain name, enter your domain name.
- Click Add another name to this certificate.
- Enter a wildcard for any subdomain. E.g., *.examplepod.com
- Validate the domain using DNS validation. AWS can automatically create the required entries in Route 53. Just follow the instructions.
- Save the ARN of your newly created certificate (you will need it in your Terraform configuration later).
Create a wildcard certificate for your domain.
Finally, you must create a second wildcard certificate in the US East N. Virginia (us-east-1) region. AWS Cloudfront can only access certificates created in the us-east-1 region. Change the region, and repeat the steps from when you created your first certificate. Save the ARN of your second certificate.
To allow Github to manage deployments to your AWS server cluster, you need to provide it with access keys and our
passwords.yaml file from the Serverpod project. You can use the same AWS access keys as you used to configure AWS CLI or generate a new pair.
Sign in to Github and find your project’s settings. Navigate to Secrets > Actions. Here you need to add three secrets for deployment to work correctly.
AWS_SECRET_ACCESS_KEY are your AWS credentials. Github also needs access to your
config/passwords.yaml file. Copy the contents of the passwords file and add it to
Your Github Action secrets after they have been configured.
You acquired a hosted zone id and two certificate ARNs from AWS in the previous steps. You will need these to configure your Serverpod deployment scripts. You find the Terraform scripts in your server’s
aws/terraform folder. Open up the
config.auto.fvars file. Most of the file is already configured, including your project’s name. You will need to fill in the variables:
If you deploy your servers in a region other than Oregon (us-west-2), you will need to update the
instance_ami variable. Instructions are in the configuration file. In addition, you will also need to update the region in your Github deployment file located in
By default, the Terraform scripts are configured to use a minimal setup to reduce costs for running your Serverpod. You can quickly turn on additional features, such as enabling Redis or adding a staging server by changing values in the script. You can also change these values later and redo the deployment step.
Finally, to complete your Serverpod configuration, you will need to edit the
config/production.yaml files. In these files, you replace the
examplepod.com domain with the domain you are using for your server.
Deploy your infrastructure
Your Serverpod should now be configured and ready to be deployed. Exciting times! Open up a terminal and
cd into your server
aws/terraform directory. First, you need to add an environment variable so that Terraform can correctly set the password for the Postgres database. You will find the production password for the database in your
export TF_VAR_DATABASE_PASSWORD_PRODUCTION="<MY PRODUCTION PASSWORD>"
Next, we are ready to initialize Terraform and deploy our server. You will only need to run the
terraform init command the first time you deploy the configuration.
Terraform will now run some checks and make a plan for the deployment. If everything looks good, it will ask you if you are ready to go ahead with the changes. Type
yes and hit the return key. Applying the changes can take up to five minutes as AWS creates the different resources needed for your Serverpod.
Create database tables
For your Serverpod to function correctly, you will need to create its required database tables and any tables specific to your setup. The database queries needed to set up your tables can be found in
tables.pgsql file may be empty if you haven’t added any tables to your project. Use your favorite tool to connect to the database (Postico is a good option if you are on a Mac). Connect to
examplepod.com with your domain); the user is
postgres, the port is 5432, and the database is
serverpod. Use the production password from the
Connect to the database with Postico.
Deploy your code
We now have our servers, load balancers, database, and other required infrastructure. The only missing part is that our code is not yet up and running. There are two ways to deploy the code from our Github project. We can either push the code to a branch called
deployment-aws-production or manually trigger the deployment action from the Github webpage.
If you have set up a staging server, you can also push code to a branch called
deployment-aws-staging. This will deploy your code to the staging environment.
To manually trigger a deployment, navigate to your project on the Github webpage. Click Actions > Deploy to AWS > Run workflow. This will open up a small dialog that allows you to choose which branch you want to use and if you’re going to target the production or staging servers. Next, click Run workflow. This will trigger the action to deploy your code to your Serverpod. Usually, the deployment process takes around 30 seconds to complete.
Manually deploy your server with Github actions.
Test your deployment
Your Serverpod should now be up and running! To check if everything is working, open up your web browser and go to
https://api.examplepod.com. (You should replace your
examplepod.com with your own domain name.) If everything is correctly configured, you will get a message similar to this:
OK 2022-05-19 14:29:16.974160Z
Troubleshooting and tips and tricks
Chances are that if you followed the instructions, you have a Serverpod deployment that you won't have to touch very often. However, this section gives you some pointers on where to start looking if things go wrong.
Signing in to your instances
You can find a list of your currently running EC2 instances by navigating to EC2 > Instances. Click on one of the instances to go to its summary page. From there, click Connect. On the Connect to instance page, click Connect, and AWS will open up a console window with access to your EC2 instance.
External dependencies and submodules
The deployment scripts support using submodules and external dependencies. Place any such dependencies in a directory called
vendor at the root of your Github project.
The deployment process involves a couple of steps. When you trigger a deployment from Github, the action will create a deployment and upload it to an S3 bucket. Then, CodeDeploy on AWS is triggered. You can find the logs from the Github action under the Actions tab of your project. If the deployment process fails later, those logs are available on AWS by navigating to CodeDeploy > Deploy > Deployments.