Recent Posts

How To Deploy Wordpress on Windows Azure


Here are steps needed to get Wordpress (PHP + MySQL + ) running on Windows Azure. You can deploy any PHP based application, Wordpress here as a sample PHP application but once you know this, you will be able to deploy Wordpress or any PHP application on Windows Azure.
Some of the Pre-requisites:
1. PHP Binaries for IIS (http://windows.php.net/)
2. MySQL Binaries (Without Installer) (http://dev.mysql.com/downloads/mysql/5.1.html )
2. MySQL PHP Solution Accelerator (http://code.msdn.microsoft.com/winazuremysqlphp )
3. VS2008 SP1/VS2010 Beta 2 w/ Windows Azure SDK  (via web installer microsoft.com/web )
4. Wordpress (Or any PHP Application) (wordpress.org)
5. “The Lazy Man Hello Cloud PHP” ( http://innovativesingapore.com/post/The-Lazy-Mane28099s-e2809cPHP-Hello-Cloude2809d.aspx ) [Optional but Reccomended]
Phase 1 – Setup
1. Install the MySQL PHP Solution Accelerator         
2. Extract the PHP binaries for IIS to the “php” folder in the PhpMyAdminWebRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\php”
3. Extract the Wordpress files to the “wordpress” folder in the PhpMyAdminWebRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\wordpress”
4. Extract the MySQL Binaries to the “mysql” folder in the MySQL_WorkerRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\MySQL_WorkerRole”
Phase 2 – Windows Azure Cloud Service
5. Create a new “Windows Azure Cloud Service” solution in Visual Studio.
6. Add an existing project, “PhpMyAdminWebRole” (From the Solution Accelerator), to the solution you created.
7. Add another existing project, “MySQL_WorkerRole” (Also from the Solution Accelerator,), to the solution.
8. Right click on “Roles” (Found in your “Windows Azure Cloud Service” project) and select “Add-> Web Role Project in solution” and select the project you added in your solution previously.
9. Repeat step 8, but this time, choose “Add -> Worker Role Project in solution” and select the “MySQL_WorkerRole” you added previously.
Phase 3 – Configuring MySQL_WorkerRole
*For learning purposes we shall not touch on the advance features of the MySQL_WorkerRole in the Solution Accelerator. If you do want to do more with it, please watch this video: http://microsoftpdc.com/Sessions/SVC51 .
For now, we are going to configure the worker role to have only 1 instance.
10. Open up the settings for “MySQL_WorkerRole” (Found in the Roles folder at your “Windows Azure Cloud Service” project) and change the following configurations:
Configuration SectionInstance Count: 1
Settings Section [Name, Type, Value]TableStorageEndpoint, String, http://table.core.windows.net
BlobStorageEndpoint, String, http://blob.core.windows.net
DataConnectionString, ConnectionString, UseDevelopmentStorage=true
DiagnosticsConnectionString, ConnectionString, UseDevelopmentStorage=true
ContainerName, String, mysqlphp11
FullBackupHour, String, 06:00
IncrementalBackupDuration, String, 10
RecycleThreadSleepTime, String, 300
EnableWindowsAzureDrive, String, False
EnableBackup, String, False
*Note, we will be using the Dev Fabric Storage in this walkthrough, feel free to use your cloud storage if any.

Endpoints (Name, Type, Protocol)
PeerEndpointIn, Internal, tcp
MasterElectionService, Internal, tcp
MySQL, Internal, tcp
InstanceManagerEndpontIn, Internal, tcp

Local Storage
MySQLStorage, 200MB
MySQLDatastore, 1024MB
BlobBackup, 500MB

Next up, we want to edit the behavior of the worker role such that when the worker role starts, it will update the PHP ini (configuration) file so that our PHP web role will know where is the MySQL database located in the cloud.
11. Open up MySQLAccess.cs in “MySQL_WorkerRole” project and make the following changes:
In the internal class “MySQLClient” add a string constant – relative path to your php ini file.
Code:
 
private const string REL_PATH_TO_PHP_INI = "./../../PhpMyAdminWebRole/approot/php/php.ini";

Next find the line “string masterHost = instance.IPEndpoint.Address.ToString();
“ and add the following after the line:

Code:
//Set php ini so PHP knows where is the host and port of the MySQL endpoint
FileStream fs = File.OpenRead(REL_PATH_TO_PHP_INI);
StreamReader reader = new StreamReader(fs);
//Read all text in INI File
string php_ini = reader.ReadToEnd();

//Closing resources
reader.Close();
fs.Close();

//Add in details (Host IP Address and Port)
php_ini = php_ini.Replace("mysql.default_port =", "mysql.default_port = " + port);
php_ini = php_ini.Replace("mysql.default_host =", "mysql.default_host = " + masterHost);
File.WriteAllText(REL_PATH_TO_PHP_INI, php_ini);               
string iniFile = Path.Combine(baseDir, "my.ini");
File.Copy("my.ini", iniFile, true);


[NEW UPDATE!]

I have changed the logic of the codes to use Environment Variables instead of updating the PHP INI file on runtime. Please make sure your function "public bool Start(int id)" looks something like the one below. (: The code is now easier to understand and shorter.

public bool Start(int id)
        {
            try
            {
                string baseDir = RoleEnvironment.GetLocalResource("MySQLStorage").RootPath.Replace('\\', '/');
                string dataDir = RoleEnvironment.GetLocalResource("MySQLDatastore").RootPath.Replace('\\', '/');
                string blobDir = RoleEnvironment.GetLocalResource("BlobBackup").RootPath.Replace('\\', '/');
                LogError("MySql Base directory: {0}", baseDir);
                LogError("MySql Data directory: {0}", dataDir);

                string command = Path.Combine(baseDir, @"bin\mysqld.exe");
                SetupBlobBackup(blobDir);
                if (!File.Exists(command))
                {
                    SetupAzureMySql(baseDir);
                    SetupAzureMySqlDataDir(dataDir);
                }
                MySqlConnection rootConn = GetConnection(_endpointName);
                if (IsRunning(_endpointName))
                {
                    int currentId = GetMySqlServerId();
                    if (currentId == id)
                    {
                        return true;
                    }
                    command = Path.Combine(baseDir, @"bin\mysqladmin.exe");
                    Process.Start(command, "-u root shutdown");
                }
              
                RoleInstanceEndpoint instance;

                //Get the "MySQL" instance
                instance = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MySQL"];

                //Get the port of the instance
                string port = instance.IPEndpoint.Port.ToString();
                Environment.SetEnvironmentVariable("MasterPort", port, EnvironmentVariableTarget.Process);
                //Get the IP address of the instance
                string masterHost = instance.IPEndpoint.Address.ToString();

                Environment.SetEnvironmentVariable("MasterHost", masterHost, EnvironmentVariableTarget.Process);



                string iniFile = Path.Combine(baseDir, "my.ini");
                //update the my.ini file with mysql server details
                UpdateMyIni(iniFile, baseDir, dataDir, port, id.ToString());
                ProcessStartInfo startInfo = new ProcessStartInfo(command);
                startInfo.RedirectStandardOutput = true;
                startInfo.WorkingDirectory = baseDir;
                startInfo.UseShellExecute = false;
                startInfo.CreateNoWindow = false;
                startInfo.Arguments = "--console";
                Process driver = new Process();
                driver.StartInfo = startInfo;
                driver.Start();


                StreamReader sr = driver.StandardOutput;
                string output = sr.ReadToEnd();
                while (!IsRunning(_endpointName))
                {
                    Thread.Sleep(TimeSpan.FromSeconds(10));
                }
            }
            catch (Exception ex)
            {
                LogError("Error in MySqlAccess start(): {0}", ex.Message + ex.StackTrace);
                return false;
            }
            return true;
        }

Phase 4 – Configuring Wordpress
12. Copy “wp-config-sample.php” in the “wordpress” folder to “wp-config.php” then open up “wp-config.php”
13. You may want to look at http://codex.wordpress.org/Editing_wp-config.php to know more about what each setting does.

Under the MySQL hostname section, set it to be “define('DB_HOST', ini_get("mysql.default_host").':'.ini_get("mysql.default_port"));” , without the quotes of course ;)
[NEW UPDATE!]
Under the MySQL hostname section, set it to be “define('DB_HOST', getenv("MasterHost").':'.getenv("MasterPort"));” , without the quotes of course ;)

For the rest of the settings, configure it as per normal (refer to:  http://codex.wordpress.org/Editing_wp-config.php)

Phase 5 – Deploying
14. We will use the Dev Fabric for now. Hit F5 and wait for all your instances to run.
Important : For those who want to deploy on the cloud,

Phase 6 – Database Setup + Testing
15. Navigate to your PhpMyAdmin site. (If you didn’t change any settings, it should be at http://localhost:81/PhpMyAdmin/index.php )
16. Login as root with no password.
17. Create a new database (the name for the database you defined when setting up wp-config.php, lets say “wordpressdb”) called “wordpressdb”.
18. Create new user with the credentials you set in “wp-config.php” previously and give the necessary rights. Remove the root users’ privileges after you created the new user (security concerns here.)
19. You can now proceed to your WordPress app to test! (Default: http://localhost:81/wordpress/index.php)  WordPress will detect whether the app have been set up or not and prompt you accordingly. Enjoy your new PHP Application using MySQL on Windows Azure Cloud!