Phoenix is an incredibly powerful, fast, and flexible web framework built in Elixir. It benefits from Elixir's use of the Erlang VM, known for running low-latency, distributed and fault-tolerant systems. Microsoft Azure is Microsoft's cloud offering built for deploying and managing applications on their global network of data centers.
In this article, I'm going to walk through deploying a Phoenix application to Azure using Nanobox. Nanobox uses Docker to build local development and staging environments, as well as scalable, highly-available production environments on Azure.
Setup Your Phoenix Project
Whether you have an existing Phoenix project or are starting the scratch, the process of configuring it for Nanobox is the same.
Note: In this tutorial, I'll be using Phoenix 1.3. If using 1.2, just change all the
phx references to
Add a boxfile.yml
Nanobox uses the
boxfile.yml to build and configure your app's environment both locally and in production. Create a
boxfile.yml in the root of your project with the following:
run.config: engine: elixir dev_packages: - nodejs - inotify-tools cache_dirs: - node_modules extra_path_dirs: - node_modules/.bin fs_watch: true deploy.config: extra_steps: - mix phoenix.digest before_live: web.main: - mix ecto.create --quiet - mix ecto.migrate data.db: image: nanobox/postgresql:9.5 web.main: start: node-start mix phx.server
This includes everything Phoenix needs to run. You may need to update a few items specific to your project, but in this walk-through, I'm going to use:
- An Elixir runtime
- Node.js packages and settings for Brunch asset compilation
- Filesystem watching for local code reloading
- Inotify for local filesystem notifications and code reloading
- Static asset digest generation on deploy
- Database creation/migration on deploy
- A Postgres database
- A web component that acts as a public webserver when deployed
Start the Local Dev Environment
boxfile.yml in place, you can fire up a virtualized local development environment. I recommend adding a DNS alias just so the app will be easier to access from a browser.
# Add a convenient way to access the app from a browser nanobox dns add local phoenix.local # Start the dev environment nanobox run
Nanobox will provision a local development environment, spin up a containerized Postgres database, mount your local codebase into the VM, load your app's dependencies, then drop you into a console inside the VM.
Generate a New Phoenix Project
If you have an existing Phoenix project, you can skip this section. To generate a new Phoenix project from scratch, run the following from inside the Nanobox console:
# cd into the /tmp dir to create an app cd /tmp # Install Phoenix mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez # Generate a new Phoenix application mix phx.new app #(Do not fetch dependencies at this moment) # cd back into the /app dir # Enable the hidden files shell option # Copy the generated app into the project dir cd - shopt -s dotglob cp -a /tmp/app/* .
Your project's current working directory is mounted into the
/app directory in the VM, so all the Phoenix files written there will propagate back down to your machine's filesystem and vice versa.
Update the Database Connection
When Nanobox spins up a Postgres database, it generates environment variables for the necessary connection credentials. Update the database connection in your
# Configure your database config :app, App.Repo, adapter: Ecto.Adapters.Postgres, username: System.get_env("DATA_DB_USER"), password: System.get_env("DATA_DB_PASS"), hostname: System.get_env("DATA_DB_HOST"), database: "gonano", pool_size: 10
gonano database is created as a default database when Postgres is provisioned, but you're welcome to create your own and use that.
Fetch Application Dependencies
To load your app's dependencies, run the following from the root of your project:
Fetch Asset Dependencies
Phoenix uses Brunch for asset compilation, which is installed as a Node.js package. Both
yarn are included in the
nodejs extra_package. I recommend using
yarn, since it's a lot faster than
If you're working with an existing Phoenix project, Brunch will have been installed as your app was built and installed in the dev environment. If you started from scratch, run:
cd assets && yarn install cd ../
Run Your Database Migration
With a fresh Postgres install, you'll need to create your database structure.
Run Phoenix Locally
With your database connection updated and dependencies loaded, you're ready to start Phoenix in your local dev environment. From the
/app directory in your Nanobox console:
You'll then be able to access your running Phoenix app at phoenix.local:4000.
Whenever you exit out of the Nanobox console, it'll shut your VM down and drop you back into your host OS.
Prepare Phoenix for Deploy
Before you deploy the project, make sure the app is listening on port
8080. This is configured in your
config :app, AppWeb.Endpoint, http: [port: 8080], load_from_system_env: true, url: [host: "example.com", port: 80], cache_static_manifest: "priv/static/manifest.json"
Starting Phoenix in Production
You should already have a web component included in the
boxfile.yml above. This tells Nanobox to create a publicly accessible webserver when the app is deployed. Notice that the web component's start command is prepended with
web.main: start: node-start mix phx.server
node-start is a helper included in Nanobox Elixir engine that ensures nodes are started with credentials sufficient to cluster and attach to after they are running. Using this, you'll be able to scale your web component into a horizontal cluster without any extra configuration.
Alright! Now to the fun part!
Setup Your Azure Account
If you haven't already, create a Microsoft Azure account. In your Azure Portal, click on "More Services" at the bottom of the left nav and filter for "Subscriptions". Click on your Subscription ID.
Copy and store your Subscription ID. You're going to need it later.
Register Resource Providers
Inside your Subscription ID options, filter for and select "Resource providers". Register "Microsoft.Compute", "Microsoft.Network", and "Microsoft.Storage" by clicking on the "Register" button to the right of each option. These are the resources necessary for Nanobox to build and provision your application on Azure.
Get Your Active Directory ID
In the left nav, select "Azure Active Directory" and go to "Properties". Copy the "Directory ID".
Copy and store your Active Directory ID. You're going to need it later.
Create a New Application Registration
Still inside Azure Active Directory, select "App Registrations" and create a new app registration. An "App Registration" is essentially an API integration. You're giving Nanobox access to your Azure resources through a registered "app".
Enter the required information:
Name - This can be whatever you'd like.
Application type - Web app / API
Sign-on URL - This isn't used by Nanobox, so put whatever you'd like.
After saving your new app registration, Copy and store your Application ID. You're going to need it later. Click on your new app registration in your list of registered apps, then select "Keys". Provide a key description and expiration, then save.
Copy and store the key value. You won't be able to retrieve it after you navigate away from this section and you're going to need it later.
Create a New Provider Account
In your Nanobox dashboard, go to the Hosting Accounts section of your account admin and click "Add Account", select Azure, and click "Proceed".
Enter the required credentials.
Subscription ID - Azure Subscription ID
Tenant ID - Azure Active Directory ID
Application ID - Azure Application ID
Authentication Key - Azure Application Registration Key Value
Cloud Environment - Should be set to
Click "Verify & Proceed". Name your provider, select your default region, then click "Finalize/Create".
Launch a New App
Go to the home page of your Nanobox dashboard and click the "Launch New App" button. Select your Azure provider from the dropdown and choose the region in which you'd like to deploy your app.
Confirm and click "Let's Go!" Nanobox will order an server on Azure under your account. When the server is up, Nanobox will provision platform components necessary for your app to run:
- Load-Balancer: The public endpoint for your application. Routes and load-balances requests to web nodes.
- Monitor: Monitors the health of your server(s) and application components.
- Logger: Streams and stores your app's aggregated log stream.
- Message Bus: Sends app information to the Nanobox dashboard.
- Warehouse: Storage used for deploy packages, backups, etc.
Once all the platform components are provisioned and running, you're ready to deploy your app.
Stage Your App Locally
Nanobox provides "dry-run" functionality that simulates a full production deploy on your local machine. This step is optional, but recommended. If the app deploys successfully in a dry-run environment, it will work when deployed to your live environment.
nanobox deploy dry-run
More information about dry-run environments is available in the Dry-Run documentation.
Add Your New App as a Remote
From the root of your project directory, add your newly created app as a remote.
nanobox remote add app-name
This connects your local codebase to your live app. More information about the
remote command is available in the Nanobox Documentation.
Deploy to Your Live App
With your app added as a remote, you're ready to deploy.
Nanobox will compile and package your application code, send it up to your live app, provision all your app's components inside your live server, network everything together, and voila! Your app will be live.
Manage & Scale
Once your app is deployed, Nanobox makes it easy to manage and scale your production infrastructure. In your Nanobox dashboard you'll find health metrics for all your app's servers/containers. Your application logs are streamed in your dashboard and can be streamed using the Nanobox CLI.
Although every app starts out on a single server with containerized components, you can break components out into individual servers and/or scalable clusters through the Nanobox dashboard. Nanobox handles the deep DevOps stuff so you don't have to. Enjoy!
Nanobox Documentation Links
Subscribe to Nanobox
Get the latest posts delivered right to your inbox