How to deploy a Swift backend on Amazon AWS

Gianpiero Spinelli
11 min readApr 4, 2019

--

Have you ever heard the word “backend”? If this is your first time hearing this strange word and you are wondering if it is an animal or a particular kind of plant or even a really tasty food, or if you know what that is but you feel like you don’t really know much about it, follow me during this guide, and in the end you will be quite an expert about it.

At the end of this guide, you will have a basic backend for your application. To reach this goal, we are going to use Kitura, a server-side web framework that allows us to build a server using Swift, for API’s endpoints, Postgres, an open source relational database, for storing data and Docker to manage the resources.

Probably now you are WAT?! What is an API Endpoint? I’ll help you!

An API is a programmatic interface consisting of one or more publicly exposed endpoints to a defined request–response message system, typically expressed in JSON, which is exposed through HTTPS protocol.

In this guide, we are going to use HTTP instead of HTTPS, because, in order to support the apparently irrelevant letter, in the end, there are a lot of hard and long steps.

At the end, we will have three API endpoints. We will be able to query these endpoints getting a JSON response. The database is a database made by three tables, that describe the structure for a travelling app.

Action!

Here we are. First of all, there are some prerequisites needed. For Kitura, if you are using macOS, you need to install Xcode 9 or later, and run xcode-select --install on the Terminal. If you are using Linux, follow this guide.

To proceed, you are going to need some other packages on your computer. I recommend installing Homebrew, a packet manager that simplifies your life with used-to-be-messy installations.

Now that everything is set up, install Kitura through Homebew:

$ brew tap ibm-swift/kitura
$ brew install kitura

Now it’s time to install Docker, a powerful tool that helps you managing scalable backends, and deploy it with ease. Download Docker and install it following the in-app steps. Take your time, and once it’s installed, login in and come back here.

You just installed everything you need, congratulation! Now we need a project folder. Our hierarchy is composed of a main folder called “MyFirstBackend”. In it, we are going to create two other folders: “backend”, “certificates” and “database”.We will use these folders to store the rules for the images of the docker containers. Later, in the database folder, we will put the rules to create the… guess it: database. In the backend folder, instead, we will instantiate the Kitura project. Seems fun, right? Let’s dig into it!

Postgres, it’s your turn!

Docker, as said before, is a really powerful program that performs operating-system virtualizations. We are using it because we will deploy our backend on the cloud. In this way, you will not care about memory, space and all the limitations of a normal web hosting. This is possible thanks to the cloud and the scalability of it.

Let’s build the database now! In the “database” folder we are going to give the rules for the Postgres database. Go back to the Terminal, and cd the database folder. In there create the Dockerfile and a SQL file

$ cd path/to/database/
$ touch Dockerfile
$ touch CreateDB.sql

Two files have been created in the database folder. One is the Dockerfile, a file with all the instruction for the creation of the Docker image, and the other one is a supporting file that we need to create the actual database structure. Let’s open the Dockerfile. Now that you have an empty text file in front of you, let’s write some instructions for the Docker container.

FROM postgres:latestENV POSTGRES_USER root
ENV POSTGRES_PASSWORD admin
ENV POSTGRES_DB myFirstDatabase
ADD CreateDB.sql /docker-entrypoint-initdb.d/

When we will build these rules, Docker will download the latest Postgres image from DockerHub, will create a user for the database with root as username and admin as password. The name of the database will be myFirstDatabase. Everything will be based on the CreateDB.sql file we created a minute ago.

Now it’s time to create the database structure.

This is the structure we are going to use. There are three tables: users, places and trips.

With the first command, we create the users table, which has:

  • user_id: the autoincremetal (SERIAL) primary key
  • username, email, password: the text properties for each tuple of users
  • username, email: these properties are marked UNIQUE, which means that will not be possible to insert a value that already exists

Then we populate the users table with a bunch of values. We have made the same process to create the places table. After this, we have created the third table called trip which is a relationship between the previous two tables. In this table, we have 2 fields that are depending on the other tables, and we do this with the FOREIGN KEY () REFERENCE () syntax.

Kitura, I choose you!

Just move in the backend folder and use Kitura to generate a ready to build OpenAPI project on the spot:

$ cd path/to/backend/
$ kitura init

Now open the generated Xcode project. To communicate with the database, we need to import some frameworks. In the Package file, import these two IBM’s frameworks and update the dependencies. The first one stands for “Object Relational Mapping” and it will facilitate us with the queries to our database. The second one is needed since we use PostgreSQL. Be aware that for advanced custom queries you would opt for using directly Swift-Kuery rather than Swift-Kuery-ORM.

.package(url: "https://github.com/IBM-Swift/Swift-Kuery-ORM.git", from: "0.4.1"),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery-PostgreSQL.git", from: "2.1.0")
.target(name: "Application", dependencies: ["SwiftKueryPostgreSQL", "SwiftKueryORM", ...

You have to regenerate the project for the new dependencies. First, close Xcode and use these commands:

$ cd backend/
$ swift package generate-xcodeproj

Reopen the project, you can now import them within the Application.swift file:

import SwiftKueryORM
import SwiftKueryPostgreSQL

Now let’s prepare our model to relate to the database. We need it to conform to Codable, Equatable and Model protocols:

  • Codable: it allows the struct to be exported in JSON
  • Equatable: it allows to compare for equality different User objects
  • Model: this exposes new methods for saving, finding, deleting etc. from a database

Now we have to establish the connection to the database. Insert this function within the App class in Application.swift:

Just change the parameters accordingly with your databaseName, userName and password.

Now let’s support GET requests in two variants within the App class:

Hey, you are ready to go!

Docker: how to!

At this point you should have a structure like this:

Now we have all the Dockerfiles we need. Some lines above we created the Dockerfile for our database, and then we instantiated a Kitura project, that creates a Dockerfile automatically. This Dockerfile misses a variable. Open the file you can find in the backend folder, remove everything and write:

FROM ibmcom/kitura-ubuntu:latest
RUN mkdir /external && apt-get update && apt-get -y upgrade && apt-get -y install curl
RUN curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
RUN apt-get update && apt-get -y upgrade && apt-get install -y nodejs libpq-dev
RUN npm install -g yo
EXPOSE 8080
ENV DATABASE_URL 127.0.0.1
ADD ./ /external/
RUN ["/bin/bash", "-c", "cd /external/; swift build"]
CMD ["/bin/bash", "-c", "cd /external/.build/x86_64-unknown-linux/debug/; ./backend"]

Now we just have to build the docker images. In order to achieve that, we need to run some commands. First of all, run docker opening the app, we installed at the beginning. When it is running, go back to Terminal and change directories to the main project’s folder (myFirstBackend). To finally build the images, you need to run these commands:

docker build -t username/mydatabase:v1 ./database
docker build -t username/mybackend:v1 ./backend

Where:

  • username: the username of your DockerHub account
  • mydatabase — mybackend: name of the images
  • v1: tag of the version you are building

You can test your images by running them on your machine. The database needs to run on port 5432:

docker run -p 5432:5432 username/mydatabase:v1

When the database is running, run the backend on port 8080, and change the environment variable with your local IP. To find your local IP, open System Preferences, then go to Network, and look at your current IP address. Set that address as DATABASE_URL:

docker run -p 8080:8080 -e DATABASE_URL='' username/mybackend:v1

When this step is done, you need to upload these images on DockerHub with:

docker push username/mydatabase:v1
docker push username/mybackend:v1

Remember to replace the username with your DockerHub username.

Deploy everything

We are almost done! Now it is the moment to deploy what you have done so far, on the cloud, that in this case is Amazon AWS. First of all, you need an account there. If you don’t have one, create it here. Once you have one, login, and, under services, select EC2. On the top right, you can select the region of the server you want to work on. In this tutorial, we are using US. West (N. California) but you can decide the one which better suits your needs.

To run your docker images on AWS you need an instance. To create one, select Instances in the menu on the left and a select the “Launch Instance” blue button in the middle of the page.

Now it is time to configure your machine. Choose Amazon Linux 2 AMI by clicking the Select button.

Technical specifications are important for your instance since they determine the limit of your app.

Configure the security group and stay away from bad and unexpected scenarios. Open just the ports you need to run your backend. The HTTP is the protocol you will use to load the API, so the source is set to everywhere so the service will be accessible from everywhere.

Note: For testing purposes, we are setting SSH sources to anywhere, but for a better security, the SSH port should be opened just for your IP Address. In this way, no one can access your instance via SSH.

Once you reviewed all the details, click Launch. In this way, you will deploy the instance and you will be able to create a pair of keys you will need to login with SSH from your terminal. Select Create a new key pair and then give it a name (in this case “debug_tutorial”). Then download the key pair, remove the .txt extension from the file and put it in the certificates folder. We will come back there later.

Done. A green success message should appear on the page. Your instance is now running on the cloud. The problem is that anything will be loaded since it is empty. Let’s fill it up!

First of all, we need the CLI (Command Line Interface) for Amazon AWS. Open again the terminal and, using Homebrew, the only command you need to run is:

$ brew install awscli

Once it is done, you have to configure your aws details with:

$ aws configure

The first input you will need is your Access Key ID, that you can find by clicking on your name in the menu on the top right, and then on “My Security Credentials”. There, select Access key, create one and download the file. Put the downloaded file in the certificates folder. Now you have two keys: the Access Key ID and the Secret Key. The next data you will need for the configuration is the Default region name that needs to reflect the region you selected in the beginning (in our case is us-west-1). Here you can find a list of available regions:

ap-northeast-1 - Asia Pacific (Tokyo)
ap-northeast-2 - Asia Pacific (Seoul)
ap-south-1 - Asia Pacific (Mumbai)
ap-southeast-1 - Asia Pacific (Singapore)
ap-southeast-2 - Asia Pacific (Sydney)
ca-central-1 - Canada (Central)
eu-central-1 - EU Central (Frankfurt)
eu-west-1 - EU West (Ireland)
eu-west-2 - EU West (London)
eu-west-3 - EU West (Paris)
sa-east-1 - South America (Sao Paulo)
us-east-1 - US East (Virginia)
us-east-2 - US East (Ohio)
us-west-1 - US West (N. California)
us-west-2 - US West (Oregon)

Set Data output format as text and the configuration is done. Now you need to connect to your instance through SSH. To do this you need to run the command below, where i-0f2103a2a2417f4cd is the id of your instance.

$ aws ec2 get-console-output --instance-id i-0f2103a2a2417f4cd

In Terminal change directories to the certificates folder that contains the .pem file created earlier. In here you have to run this command, where debug_tutorial is the name of your certificate.

$ chmod 400 debug_tutorial.pem

Let’s connect to the instance finally! Run this command:

$ ssh -i debug_tutorial.pem ec2-user@ec2-13-57-229-28.us-west-1.compute.amazonaws.com

Since we selected “Linux “ at the beginning, the user is ec2-user. After the @, the DNS name is the Public DNS that you can find in the description of the instance. The debug_tutorial.pem, instead, is the name of your certificate. After this, enter yes and everything is set.

Now you are connected through SSH to your instance. It’s time to install docker on the machine:

sudo yum update -y
sudo amazon-linux-extras install docker

Start the docker service:

sudo service docker start
sudo usermod -a -G docker ec2-user

Logout with logout and log back in and then check the docker’s installation:

docker info

Now install and run the two containers:

docker run -p 5432:5432 username/mydatabase:v1
docker run -p 8080:8080 -e DATABASE_URL='' username/mybackend:v1

The DATABASE_URL is the public IP of your instance.

Everything is up and running! Congratulations! Now you can access your API through the public IP address.

--

--