Deploy your API
It's finally time to deploy our service to a real-life server.
Emily supplies easy-to-use commands for deploying and re-deploying your services to both standard servers with SSH access, as well as Kubernetes clusters.
For this tutorial, we'll use a standard Ubuntu server to which we have SSH access.
Adding a server
As long as the host server is running Ubuntu >= 18.04, Emily is host-agnostic. As such, any server you have SSH access to is a valid deployment target.
The only requirements are:
- You know the IP or domain name to your server
- You have the SSH key to your server
- You know the username associated with the SSH key
If you're a student, you can get credits to a large number of cloud providers through the GitHub Student Developer Pack.
Emily needs to know about your server. To add it, simply run emily servers
and choose + Add server
.
$ emily servers
? Emily: Add new server to emily, select a server to configure, or remove existing
(Use arrow keys, confirm with ENTER)
…
> + Add server
- Remove server
· + Add server
√ Emily: What is the server's IP or Domain name?:
· demo.ambolt.io
√ Emily: What username should be used on the server?:
· root
√ Emily: Path to the SSH key to the server?:
· ~/.ssh/id_rsa
√ Emily: What do your want Emily to name the server?:
· My Demo Server
Specifying a deployment
We very briefly mentioned deployments as a core concept in Exploring the project.
Recall that a deployment (specified under ./deployments
in your project files) specifies:
- What configuration to deploy
- Under which environment
- To which target
We already have a dev
configuration and dev
environment, as Emily creates these by default.
Adding an environment
Let's create a new environment to deploy our service under called prod
:
$ emily environment
--project my-project
? Emily: Please select an action:
(Use arrow keys, confirm with ENTER)
…
> + Add a new environment
* Update an existing environment
- Remove an existing environment
· + Add a new environment
√ Emily: Please enter the environment name:
· prod
√ Emily: Please enter a port:
· 4242
? Emily: Use a GPU in this environment?
(y/N) · No
√ Emily: Please enter the number of workers:
· 2
Emily: Environment "prod" added to project my-project (66AWNR)
Created:
- <...>/my-project/environments/prod/.emily.env
Adding a configuration
Let's also create a new configuration in case we need server-specific configurations:
$ emily configuration
--project my-project
? Emily: Please choose an action:
(Use arrow keys, confirm with ENTER)
…
> + Add a configuration
- Remove a configuration
· + Add a configuration
? Emily: Please select a configuration:
(Use arrow keys, confirm with ENTER)
…
dev
> + Add new configuration
· + Add new configuration
√ Emily: Please enter the configuration name:
· prod
? Emily: Please choose a configuration type
(Use arrow keys, confirm with ENTER)
…
> Docker Compose configuration
Kubernetes configuration
· Docker Compose configuration
? Emily: Please choose a Docker Compose configuration:
(Use arrow keys, confirm with ENTER)
…
> Base
HTTPS reverse proxy (Nginx)
External network
· Base
Emily: Compose configuration "prod" added to project my-project (66AWNR)
Created:
- <...>/my-project/configurations/prod/docker-compose.emily.yml
Adding a deployment
Now, let's define a new deployment using our newly created environment and configuration, targeting the server we added in the prior step:
$ emily deployment
--project my-project
? Emily: Please select an action:
(Use arrow keys, confirm with ENTER)
…
> Add a new deployment specification
· Add a new deployment specification
√ Emily: Please enter a deployment name:
· my-server-deployment
? Emily: Please select a configuration:
(Use arrow keys, confirm with ENTER)
…
dev
> prod
+ Add a new configuration
· prod
? Emily: Please select an environment:
(Use arrow keys, confirm with ENTER)
…
dev
> prod
+ Add a new environment
· prod
? Emily: Please select the type of deployment to create a specification for:
(Use arrow keys, confirm with ENTER)
…
Local - deploy on your local system
> Server - deploy to a server with SSH access
Kubernetes - deploy to a Kubernetes cluster
· Server - deploy to a server with SSH access
? Emily: Select or create a server:
(Use arrow keys, confirm with ENTER)
…
+ Add server
> Name: My Demo Server
IP/Domain: demo.ambolt.io
Status: Online
· Name: My Demo Server
IP/Domain: demo.ambolt.io
Status: Online
Emily: Server deployment "my-server-deployment" added to project my-project (66AWNR)
Created:
- <...>/my-project/deployments/my-server-deployment/deploy.sh
- <...>/my-project/deployments/my-server-deployment/deployment.json
- <...>/my-project/deployments/my-server-deployment/post_deployment_hook.sh
Deploying your service
Now that we have specified a deployment targeting our server, there's nothing left to do expect execute the deployment.
To do this, run the emily deploy
command:
$ emily deploy
--project my-project
? Emily: Please select a deployment specification:
(Use arrow keys, confirm with ENTER)
…
local
> my-server-deployment
+ Add new deployment specification
· my-server-deployment
? Emily: Use the specified deployment and configuration?
(Use arrow keys, confirm with ENTER)
…
> Current
- Environment: prod
- Configuration: prod
+ Choose different environment/configuration
· Current
- Environment: prod
- Configuration: prod
Emily: Deploying my-project (66AWNR) using:
Deployment: my-server-deployment (server)
Environment: prod
Configuration: prod
Checking internet connection...
Verifying the deployment
Once the Emily command finishes, your service should be successfully deployed.
You can verify your deployment by visiting your API at http://
If you cannot connect to your API just yet, don't worry! There might be a couple of easy-to-fix issues getting in the way.
Ensuring open ports
You might not be able to connect to your API because the specified port 4242
is not open on the server.
If you're using a server from an open cloud provider, e.g. DigitalOcean, take the following steps to allow port 4242 traffic through the firewall:
- SSH into your server
- Run
ufw allow 22
to allow OpenSSH connections - Run
ufw allow 4242
to allow connections on port 4242 - Run
ufw enable
If you're using a more managed cloud provider, e.g. Azure or AWS, you may need to allow traffic by adding the necessary network security rules in the Azure or AWS control dashboards.
Ensuring IP is whitelisted
If you're using a managed cloud provider like Azure or AWS, connections to your server might be limited to an IP whitelist that your current IP is not on. Consult your provider's documentation on allowing traffic.
Testing your API
Let's try and get a stock market prediction out of our API. Execute the following request:
curl -X POST 'http://<your-ip-or-domain>:4242/predict' \ --header 'Content-Type: application/json' \ --data-raw '{ "ticker": "AAPL", "open": 19.1, "high": 25.312, "low": 18.2 }'
If you receive a reponse similar to the following, your API is officially live:
{ "close": 0.7231, "confidence": 0.01323 }
Congratulations!
Your API should now be live and accessible by the rest of your infrastructure.
While this is fine for testing, this isn't quite production-ready since all communication to your API remains unencrypted and, therefore, unsafe. Let's fix that in the next section: Securing your API with HTTPS and Nginx.