When running your app in production, you can improve performance by serving static assets such as images, CSS and JS from a content delivery network (CDN). The CDN caches your content in servers close to your customers, improving network latency.
Phoenix is fast, but the more requests handled by the CDN, the fewer requests your server needs to handle, allowing it to focus on dynamic content. A CDN like CloudFlare can also protect your app from DDOS attacks.
Serving static assets from Nginx
If you are running your app behind Nginx,
configure Nginx to serve the static files. Set the
root dir in the vhost to
point to the
priv dir in the release:
Serving assets from a CDN
Many CDNs work as a read-through cache. If the CDN gets a request for a file that is not in its cache, then it contacts the app to get it, then caches it. With others, you have to separately upload assets to the CDN when deploying.
In a simple app deployed to a single server, we deploy the app and its assets together, so the assets are always in sync with the code.
With HTTP-level caching, by definition, the cache will serve an old version of the file. As you make changes to your static assets, you need to make sure that the application uses the version of the assets corresponding to the version of the code that's running.
If you deploy a new version, the code should use the new assets. If you roll back, it should go back to the old version. Similarly, if you are doing a Blue / Green rolling deploy of your app in an auto scaling group, you will have a mix of old and new app versions sharing the CDN.
Building static assets in Phoenix
Fortunately, Phoenix handles the process of generating unique names for
your assets. It maps a generic name like
/js/app.js in your template
into a versioned name like
When we update the assets, they get a unique id, and the client will load get the new version. The unique filenames mean that multiple versions of the same file can coexist in the cache.
We can also set the cache lifetime to infinity everywhere, as they will never change. This lets the browser and other caches keep them around longer for better performance.
TODO: cache headers
The first step is to compile your application assets for production
mix deps.get --only prod MIX_ENV=prod mix compile MIX_ENV=prod mix phx.digest
This builds assets under
priv/static. When we deploy a new release to production,
we need to copy the new asset files into the CDN.
For example, we can sync the files to the S3 bucket backing your CloudFront distribution.
aws s3 sync priv/static s3://$CDN_ASSETS_BUCKET
In order to use the CDN, Phoenix needs to generate URLs that point to it.
First, we set up a DNS
CNAME record pointing
the URL of your CDN.
If you are using Amazon AWS and CloudFront CDN, then you should use Amazon
Route53 for your DNS, as it supports a special
ALIAS record that works like a
CNAME, but follows the underlying resource if it changes.
Route53 also allows you to alias bare domains, e.g. http://example.com/, which
is otherwise not allowed. This is particularly useful for high volume sites,
where we want to reduce the amount of data transferred. Make a separate domain
http://foocdn.com/ to serve your static assets, and it will not have the
cookies associated with your main domain. And you can shave off the subdomain at
the front, every byte helps :-).
Configuring Phoenix to use the CDN
Configure your app to use the CDN by setting the
parameters in the endpoint config.
See this article for more details.
Getting the user's public IP
When you are running behind a CDN, requests will look like they come from the CDN. In order to get the user's actual IP, we need to look at the headers set by the CDN.