Hosting TX Native CDS on Heroku

Nikos Vasileiou
September 21, 2021
6 min read

Host Transifex in Heroku

Transifex Native is a modern approach to app localization, with over-the-air updates, and hassle-free content management in the cloud, powered by a set of SDKs empowering localization straight in the code.

One of the core components of the solution is the Content Delivery Service (CDS), an open-source service, responsible for the delivery of localized phrases over-the-air to the end-user. CDS connects to Transifex TMS and optimizes storage, caching and delivery on the edge.

Out of the box, Transifex Native SDKs connect with a shared CDS offering, which is hosted, optimized and scaled by Transifex itself on AWS.

There are cases though, where a Transifex Native customer is looking for more control and/or ownership of the uptime and delivery of translations. This is where the CDS self-hosting option comes into play. 

This blog post is all about explaining the steps of installing and running CDS on Heroku, one of the easiest and most popular platforms to run and deploy code, without the operational fuss.

In this step-by-step tutorial, we proceed by assuming that you already have a Heroku account with Heroku CLI installed and authenticated in a terminal environment.

Set up the Heroku Environment

As a first step, we will need to create a new Heroku app. Skip this step if you have already created a new app from the Heroku UI. For the sake of this example we’ll use the tx-cds app slug, which should be unique amongst the Heroku platform, so feel free to use any other name if needed.

Through the terminal run the following command to create a new Heroku app:

heroku apps:create tx-cds

And set the stack to container, as we will be using the stock CDS Docker image for the service.

heroku stack:set container -a tx-cds

Create a Redis instance

CDS requires a Redis instance as a datastore and a message broker. Heroku offers a Redis addon, and in this example we will use their free plan. To provision the addon, run the following command in the terminal:

heroku addons:create heroku-redis:hobby-dev -a tx-cds

Redis connection settings are now made available to our app via the REDIS_URL environment variable.

Configure Settings

Heroku assigns dynamic ports to the running services, exposed in the PORT environment variable. To enable this for the CDS we will need to create two environment variables, mapping the PORT and the REDIS_URL environment variables to the CDS related settings:

heroku config:set TX__APP__PORT=\$PORT -a tx-cds
heroku config:set TX__REDIS__HOST=\$REDIS_URL -a tx-cds

Deploy the Service

With the Heroku environment being set up, the last step is to deploy the actual service using the official CDS Docker image. Deployments on Heroku happen through Git, so we need to set up a simple Git repo through the following steps:

mkdir tx-cds
cd tx-cds

Create a new heroku.yml file and add the following content:

build:
  docker:
    web: Dockerfile

Create a new Dockerfile file and add the following content:

FROM transifex/transifex-delivery:latest

Setup the git repository using the following commands:

git init
heroku git:remote -a tx-cds
git add Dockerfile heroku.yml
git commit -m "Transifex Delivery"

Start the deployment by pushing to Heroku remote:

git push heroku master

Test that the service is running by querying the health endpoint:

curl -X GET https://tx-cds.herokuapp.com/health

And try to fetch some actual content from the Transifex Native Sandbox environment using the command:

curl -X GET -H "Authorization: Bearer 1/066926bd75f0d9e52fce00c2208ac791ca0cd2c1" -v https://tx-cds.herokuapp.com/languages -L

Configure Native SDKs

All Transifex Native SDKs connect by default to the Transifex hosted CDS. To take advantage of our new setup, we need to update the SDKs with the new Heroku endpoint. For example, in the Javascript SDK we would do the following:

import { tx } from '@transifex/native';

tx.init({
  token: '1/066926bd75f0d9e52fce00c2208ac791ca0cd2c1',
  cdsHost: 'https://tx-cds.herokuapp.com',
});

Or when pushing from the CLI:

npx txjs-cli push src/ --cds-host=https://tx-cds.herokuapp.com

You may find similar options in the other Transifex Native SDKs, such as the Python, iOS or Android SDKs.

Secure CDS (optional)

By default, our new self-hosted CDS instance will fetch, cache and serve ANY active Transifex Native Project, similar to the default Transifex hosted instance. You can limit access to your own Native projects by using the whitelisting functionality, through the:

TX__SETTINGS__TOKEN_WHITELIST=token1,token2,...

environment variable. On Heroku, this can be done through the following command:

heroku config:set TX__SETTINGS__TOKEN_WHITELIST=1/066926bd75f0d9e52fce00c2208ac791ca0cd2c1 -a tx-cds

After calling the command, CDS will only serve content related to the 1/066926bd75f0d9e52fce00c2208ac791ca0cd2c1 project token and return a permission error for all the others.

Scale delivery using Amazon S3 and Cloudfront (Optional)

In the setup of this tutorial, all localized content is cached in our Redis instance and served to the end user by the CDS service itself. Production and high traffic systems can take advantage of CDN services such as AWS Cloudfront or Fastly, that can propagate content around the globe, with tremendous impact in the response times of content delivery.

CDS has already built-in support for storing content on AWS S3, apart from Redis. Assuming that you have an AWS account, you may provision an S3 service and create an S3 bucket, e.g. tx-cds-bucket, setting the proper permissions for public access. There is a related tutorial by Heroku on how to set up AWS S3 for storing static assets that you may find useful.

With S3 and related credentials in place we need to update our config variables to enable S3 support:

heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy -a tx-cds
heroku config:set TX__CACHE__S3__BUCKET=tx-cds-bucket -a tx-cds
heroku config:set TX__CACHE__S3__ACL=public-read -a tx-cds
heroku config:set TX__CACHE__S3__LOCATION=https://s3.amazonaws.com/tx-cds-bucket/ -a tx-cds

And finally switch the cache from redis to s3 using the command:

heroku config:set TX__SETTINGS__CACHE=s3 -a tx-cds

Assuming that you decide to install Cloudfront or other CDN service on top of the S3 bucket, you can update the following setting to ensure CDN delivery of content:

heroku config:set TX__CACHE__S3__ACL=private -a tx-cds
heroku config:set TX__CACHE__S3__LOCATION=https://cdn.example.com/ -a tx-cds

Next Steps 

Feel free to read the official CDS documentation on Github. You can explore more options on how to enable observability and monitoring tools and instructions on how to scale the service even more by splitting functionality to web and worker nodes.

 

Nikos Vasileiou
FacebookgithubGoogle+Fill 88Twitter