PHP is one of the most widely used programming languages in the world, known for its flexibility and ease of use. 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 PHP application to Microsoft 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 Project
Whether you have an existing PHP project or are starting the scratch, the process of configuring it for Nanobox is the same.
Add a boxfile.yml
Nanobox uses the
boxfile.yml to build and configure your app's environment both locally and in production. The most important setting in the boxfile is your
engine. An engine is a set of scripts that build and prepare your app's runtime environment. Engines also expose configuration options unique to their specific language.
The PHP engine allows you to configure settings typically defined in your
php.ini in the
boxfile.yml, keeping all your environment configuration in one place. The full list of configurable options is available the PHP Settings guides.
Nanobox takes a minimalistic approach to runtimes, so a default PHP runtime comes with only the bare-bones requirements, including a short list of core PHP extensions. To enable PHP and Zend extensions, include them in your
boxfile.yml. The full list of available extensions is available in the PHP & Zend Extensions guide.
What's required in your
boxfile.yml depends on your application, but the following example shows a boxfile for a somewhat typical PHP application.
run.config: engine: php engine.config: runtime: php-7.1 webserver: nginx document_root: public extensions: - pdo - pdo_mysql - mbstring - session - dom - ctype - xml - xmlwriter deploy.config: before_live: web.site: - phinx migrate -e production web.site: start: php: start-php nginx: start-nginx writable_dirs: - tmp/cache network_dirs: data.storage: - public/uploads log_watch: app[error]: /app/tmp/application.log data.db: image: nanobox/mysql:5.7 data.storage: image: nanobox/unfs:0.9
boxfile.yml example will:
- Provide a PHP runtime with PHP 7.1.
- Include and use Nginx as the webserver (Apache is also available).
- Set the document root to
- Include PHP extensions required for the app.
- Provide a publicly accessible webserver when deployed that runs PHP-FPM and Nginx.
- Provide a persistent network filesystem when deployed.
- Store the contents of
public/uploadsin the network filesystem when deployed.
- Stream application logs into the app's aggregated log stream.
- Provide a scalable MySQL 5.7 database.
Go ahead and create a
boxfile.yml tailored to the needs of your application and include it in the root of your project. If you're working with a framework, the Nanobox guides are a good resource for getting started. Otherwise you can view the PHP engine documentation or reach out in the Nanobox Slack channel.
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 myphpapp.local # Start the dev environment nanobox run
Nanobox will provision a local development environment, mount your local codebase into the VM, provision a containerized MySQL database, load your app's dependencies (if a
composer.json is present), then drop you into a console inside the VM.
Update Your Database Connection
In this example, I'm using MySQL, but you can use any of the officially supported data services. When Nanobox spins up a data service, it generates environment variables for the necessary connection credentials. For MySQL, host, user, and password environment variables are provided. Also, Nanobox provides a default
Update your database connection to use the auto-generated environment variables provided by Nanobox.
Database Connection Example
'mysql' => [ 'driver' => 'mysql', 'host' => $_ENV['DATA_DB_HOST'], 'port' => '3306', 'database' => 'gonano', 'username' => $_ENV['DATA_DB_USER'], 'password' => $_ENV['DATA_DB_PASS'], 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ],
Adding Other Data Components
Note: The process for adding other data components such as Redis, Memcached, Postgres, etc. is the same:
- Add the data component to your
- Add the necessary PHP extensions.
- Update your connection config to use the auto-generated environment variables.
nanobox buildto apply the changes and provision the data component.
Run Your App Locally
Ok, you should be ready to fire your app up locally. Nanobox's PHP engine includes a
php-server helper script that starts your app using settings defined in the
boxfile.yml. For this example, it'll start Nginx and PHP-FPM. Just run the following from the root of your project in the Nanobox console:
You'll then be able to access your running app at myphpapp.local.
Any changes to your codebase will be reflected in the running app. Once you're done hacking, exit out of the Nanobox console and your local dev environment will shutdown.
Prepare Your App for Production
boxfile.yml example above includes a web component and a storage component, it's important to understand that these do not get provisioned when running your app locally with
nanobox run. In this environment, you start your web process manually inside of a local "code" container. Also, storage components aren't required when developing locally since everything is writable and nothing is distributed.
Network Storage vs Writable Directories
On the topic of writable permissions and network storage, something you should be particularly aware of when deploying PHP applications with Nanobox is the fact that deployed environments are read-only.
writable_dirs allow you to change directory permissions in your live app, but it's important to understand the differences between the two.
In short, network directories are stored on a storage component and act as a shared filesystem for multi-node webs and workers that persist between deploys. They should be used for things that need to persist and/or must be consistent across all nodes in a cluster (like user uploads). Writable directories are stored on each node's local filesystem, so whatever is stored there isn't shared between nodes and will get flushed on deploy.
For the deep dive, check out these docs:
Production Start Commands
php-server helper script is great for starting your PHP app locally, but it shouldn't be used to start your app in production. Using it in production will prevent the Nanobox process manager from properly tracking PHP-FPM and Nginx/Apache. The PHP engine provides three other helpers that should be used:
start-nginx. Each of these start the appropriate processes individually, allowing them to be properly monitored by the process manager.
web.site: start: php: start-php # When using nginx nginx: start-nginx # When using apache apache: start-apache
Custom Nginx Configs
The PHP engine generates a bare-bones
nginx.conf for you. If you need to customize your Nginx configuration, the Custom Nginx Configs with the Nanobox PHP Engine article walks through how.
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