Deploying CodeIgniter on EC2 via Dokku
Using the Git post-receive hook to deploy your static site is lightweight and convenient, but doesn't quite work for applications that require backing services like a database or a file upload service.
Dokku Alternative is a more feature-complete fork of Dokku, and allows you to turn any
server into a Heroku-like platform where all you need to do is a single git push
to deploy an app.
Here is a short guide on deploying a PHP CodeIgniter app to an Amazon EC2 instance:
Create the EC2 instance
Launch an Ubuntu Server 14.04 instance, select any instance size and SSD you like, and make sure you open TCP ports 80 and 443 (HTTP and HTTPS).
Install dokku-alt
Connect to your instance via SSH and create a TCP tunnel to remote port 2000:
macbook$ ssh -L 2000:localhost:2000 ubuntu@<IP_ADDRESS>
Then run the dokku-alt install script:
ubuntu@ip-1-2-3-4:~$ sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/dokku-alt/dokku-alt/master/bootstrap.sh)"
The script will open a web server on port 2000; open http://localhost:2000, paste your public SSH key, and leave virtualhost naming disabled for now.
Prepare the CodeIgniter app
To deploy a CodeIgniter app to dokku-alt, you'll need to
set it up like a Heroku app by configuring
Composer and a Procfile
.
Add a file composer.json
with the following contents:
{"require": {"php": "~5.6.0"},"require-dev": {"heroku/heroku-buildpack-php": "*"}}
Add a file Procfile
with the following contents:
web: vendor/bin/heroku-php-apache2
Run composer update
, then your project structure should look something like this:
.├── application/├── system/├── vendor/├── .gitignore├── .htaccess├── composer.json├── composer.lock├── index.php├── license.txt└── Procfile
Deploy the app
Add a Git remote that points to your new dokku-alt instance, then push:
macbook$ git remote add dokku dokku@<IP_ADDRESS>:myappmacbook$ git push dokku
The output should then tell you where the application is deployed, for example:
...remote: =====> Application deployed:remote: http://<IP_ADDRESS>:49153...
Since we haven't enabled virtualhost naming, the app is served on an app-specific port. Only ports 22, 80, and 443 are open, so you need to open an SSH tunnel to access the app port:
macbook$ ssh -L 8080:localhost:49153 ubuntu@<IP_ADDRESS>
Then open http://localhost:8080.
Attach the database
If your application requires a database, you can use dokku-alt to create a database container for either MariaDB (a MySQL-compatible database), PostgreSQL, or MongoDB.
For example, add a MariaDB container:
ubuntu@ip-1-2-3-4:~$ dokku mariadb:create myapp
Then link it to your app:
ubuntu@ip-1-2-3-4:~$ dokku mariadb:link myapp myapp
A new DATABASE_URL
environment variable should now be configured for the app. For example:
ubuntu@ip-172-31-39-239:~$ dokku config myapp=== myapp config vars ===DATABASE_URL: mysql2://myapp:PW5HDJs0KhmoUOZH@mariadb:3306/myapp
Configure environment variables
Now that your app is deployed with a database, you need to configure it to connect using the supplied DATABASE_URL
variable. CodeIgniter does not have a built-in way to specify the database connect with a URL, so we need to parse it.
In application/config/database.php
:
<?php...$database_url = getenv("DATABASE_URL");$url=parse_url(getenv("DATABASE_URL"));$server = $url["host"];$username = isset($url["user"]) ? $url["user"] : '';$password = isset($url["pass"]) ? $url["pass"] : '';$database = substr($url["path"], 1);$db['default']['hostname'] = $server === 'localhost' ? '127.0.0.1' : $server;$db['default']['username'] = $username;$db['default']['password'] = $password;$db['default']['database'] = $database;$db['default']['dbdriver'] = 'mysqli';...
Note that the database driver is set to 'mysqli'
instead of the default 'mysql'
; the MariaDB container is
not compatible with the deprecated 'mysql'
driver.
See the full database.php here.
It would also be ideal for our app to throw an exception if the required environment variables are not set. We can use CodeIgniter hooks to check the environment before calling a controller:
Enable hooks in application/config/config.php
:
<?php...$config['enable_hooks'] = TRUE;...
Specify the hook in application/config/hooks.php
:
<?php...$hook['pre_controller'] = array('class' => '','function' => 'check_environment','filename' => 'Environment.php','filepath' => 'hooks');...
Finally, implement the hook in application/hooks/Environment.php
:
<?php/*** Ensure that environment variables are set*/function check_environment() {if (!(getenv("DATABASE_URL")))throw new Exception('Must set a DATABASE_URL environment variable');}
Add these changes and git push
them to dokku, and your application should connect to the database.