Mac as a Development platform

I sometimes feel as if I spend half my time making fixes caused by Apple upgrades.

This morning I found my previously hand-crafted php.ini had been removed.

So, each time Apple does an upgrade I have to go back in and update php.ini with various customizations (like max post size, etc).

This also happened to Apache. Apple did an upgrade and I lost my virtualhosts.

And other things change too – like I now have to use mysql.server start rather than using mysqld. I can understand that things need to change but why not provide a graphic tool and just change things under the hood.

Now I try restarting MySQL and I get:

So clearly another update has happened that I’ll need to fix.

My experience on Linux has always been much smoother. I’m starting to wonder if I should try using it again as a development platform.

How does WordPress load templates?

The short answer:

– go see https://codex.wordpress.org/Template_Hierarchy

However, here’s a worked-out example.

I have a page called News with the slug “news”.  Here’s how WordPress loads the necessary page:

1. Apache runs your root /index.php file

2. This require’s

3. wp-blog-header then:

require_once’s wp-load.php

runs wp() and

require_once’s template-loader.php

4. template-loader.php does a few checks and then runs a huge if, elseif:

Lovely!

It turns out that the example given sets $template to ‘wp-content/themes/<theme name>/page-news.php’.

How does it do that? Well, if we search for the function get_page_templates() it turns out there are 3 occurrences in the WordPress code (in wp-admin/includes/theme.php and in various wp-includes files – class-wp-theme.php, template.php).

So, which one is it using?

The answer:

wp-includes/template.php which returns the value here:

Where is get_page_template_slug() defined?

In wp-includes/post-template.php. This works out the post using the post_id.

Then it works out the template using get_post_meta() (which is defined in post.php).

get_post_meta simply returns the result of another function get_metadata which is defined in meta.php.

The full code:

In meta.php > get_metadata it checks $meta_key. It cycles through a bunch of values in $meta_cache until it gets to $meta_key = ‘_wp_mf_page_template’.

The code:

cycles through the $meta_cache values just to decide the template! I had 343 values!

I literally gave up here as, whilst I spotted a $meta_key = “_wp_page_template” it continued to cycle through the $meta_cache values. Without wasting more time on this I can only assume it found the value here.

 

 

 

 

Apache: Client denied by server configuration

This error means that the access to the directory on the hard disk was denied by an Apache configuration. It could be that access was denied due to an explicit deny directive or due to an attempt to access a folder that is outside of the DocumentRoot. It can also happen when you are proxying and there’s no access configured for the proxied location. And it is the default response to a PUT request.

To fix this problem, look at the line in your ErrorLog, to find out which folder it is trying to access. 

If a <Directory> block already exists for that folder, make sure it is set to allow access as necessary. If not, add a <Directory> block to your Apache configuration file, allowing access as required. See the example below for folder /usr/local/awstats/htdocs.

<Directory /usr/local/awstats/htdocs>

  Order allow,deny

  Allow from all

</Directory>

More: 

http://wiki.apache.org/httpd/ClientDeniedByServerConfiguration

Passenger: specifying the environment

Passenger runs in production by default.

To run in development, update your Virtual Host and set the Rails Environment variable, e.g.:

RailsEnv development

e.g. here’s my full Passenger VirtualHost config:

<VirtualHost *:80>

        ServerName server.name.here

        # !!! Be sure to point DocumentRoot to ‘public’!

        DocumentRoot “/path/to/public”

        RailsEnv development

        <Directory “/path/to/public”>

                Order allow,deny

                Allow from all

                # This relaxes Apache security settings.

                AllowOverride all

                # MultiViews must be turned off.

                Options -MultiViews

        </Directory>

</VirtualHost>

See also this discussion:

http://code.google.com/p/phusion-passenger/issues/detail?id=45

and this:

http://my.opera.com/williamn/blog/2009/03/03/how-to-make-phusion-passenger-run-in-development-mode

Passenger: 100% CPU

Possible reasons:

1. Piped logging seems to have caused a problem that’s been fixed in version 4.0.6 of Passenger

2. If you need to debug Passenger problems, use this option:

PassengerDebugLogFile <path to log>

and this to specify the log level:

PassengerLogLevel <integer – see guide>

(in Apache syntax)

passenger_log_level

(in Nginx syntax)

Apache Guide:

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_logging_and_debugging_options

Nginx Guide:

http://www.modrails.com/documentation/Users%20guide%20Nginx.html#_passenger_debug_log_file_lt_filename_gt

Rails: Phusion Passenger

Passenger is an application server for Ruby (Rack) and Python (WSGI) apps.

Some notes on installing it:

https://www.phusionpassenger.com/download

Ignore the docs that suggest:

$ sudo gem install passenger

$ sudo passenger-install-apache2-module

Instead use:

gem install passenger

passenger-install-apache2-module

Then paste the LoadModule code it spits out at the end into your Apache conf file.

Test whether Passenger has installed by running:

curl -sI localhost | grep ^Server

and check for the “Phusion_Passenger” signature. E.g. 

Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch Phusion_Passenger/4.0.5 mod_ssl/2.2.22 OpenSSL/0.9.8x

If you need to uninstall Passenger using sudo then:

$ sudo gem uninstall passenger

And a discussion on whether to use rvmsudo or not here:

https://groups.google.com/forum/#!topic/rubyversionmanager/9dnmAsTiHR4

In short, https://www.phusionpassenger.com/download

suggests using sudo but the rvm page suggests not:

https://rvm.io/integration/passenger

Note:

If you get a warning doing the passenger install apache2 module like this:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

Warning: can not check /etc/sudoers for secure_path, falling back to call via /usr/bin/env, this breaks rules from /etc/sudoers. Run:

    export rvmsudo_secure_path=1

Then run:

    export rvmsudo_secure_path=1

and:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

(remember to run rvm requirements afterwards)

On the Mac the Apache conf and restart commands go like this:

[~]$ sudo vim /etc/apache2/httpd.conf

[~]$ sudo apachectl restart

See also:

https://developer.apple.com/library/mac/#featuredarticles/PhusionRails/_index.html

and this very useful guide:

http://jasoncodes.com/posts/mac-os-rails-server

Rails: Phusion Passenger

Passenger is an application server for Ruby (Rack) and Python (WSGI) apps.

Some notes on installing it:

https://www.phusionpassenger.com/download

Ignore the docs that suggest:

$ sudo gem install passenger

$ sudo passenger-install-apache2-module

Instead use:

gem install passenger

should be sufficient and rvm.io suggests just running:

passenger-install-apache2-module

See also:

http://stackoverflow.com/questions/17245105/passenger-module-fails-to-install

and

http://stackoverflow.com/questions/17248660/installing-passenger-use-sudo-rvmsudo-or-nothing

Then, paste the LoadModule code it spits out at the end into your Apache conf file.

Test whether Passenger has installed by running:

curl -sI localhost | grep ^Server

and check for the “Phusion_Passenger” signature. E.g. 

Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch Phusion_Passenger/4.0.5 mod_ssl/2.2.22 OpenSSL/0.9.8x

If you need to uninstall Passenger using sudo then:

$ sudo gem uninstall passenger

And a discussion on whether to use rvmsudo or not here:

https://groups.google.com/forum/#!topic/rubyversionmanager/9dnmAsTiHR4

In short, https://www.phusionpassenger.com/download

suggests using sudo but the rvm page suggests not:

https://rvm.io/integration/passenger

Note:

If you get a warning doing the passenger install apache2 module like this:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

Warning: can not check /etc/sudoers for secure_path, falling back to call via /usr/bin/env, this breaks rules from /etc/sudoers. Run:

    export rvmsudo_secure_path=1

Then run:

    export rvmsudo_secure_path=1

and:

rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all

(remember to run rvm requirements afterwards)

On the Mac the Apache conf and restart commands go like this:

[~]$ sudo vim /etc/apache2/httpd.conf

[~]$ sudo apachectl restart

See also:

https://developer.apple.com/library/mac/#featuredarticles/PhusionRails/_index.html

Linode Rails Server: Debian or Ubuntu

Debian is the oldest of the Linux distributions and has a venerable history. 

But what attracts me to Ubuntu are the LTS distributions (or Long Term Support). You get a massive 5 years of support for that distribution. So, Ubuntu 12.04 LTS will be backed till 2017! Debian will support the previous release for 1 year.

Also, Ubuntu has the backing of a commercial organisation.

See also:

http://askubuntu.com/questions/15314/debian-stable-vs-ubuntu-lts-for-server

and

http://serverfault.com/questions/389199/is-it-debian-really-more-stable-for-servers-than-ubuntu-lts

and a specific guide to setting up a Rails server on Ubuntu 12.04 here:

http://blog.lunarlogicpolska.com/2013/setup-fresh-ubuntu-server-for-ruby-on-rails/

For the process of provisioning your server, see:

https://library.linode.com/getting-started

and a useful read on Phusion Passenger is:

https://developer.apple.com/library/mac/#featuredarticles/PhusionRails/_index.html

although it’s Apache-specific (e.g. it doesn’t mention Nginx).

If you’re on a Mac then use PassengerPane for local Rails deployments (helps avoid cluttered /etc/hosts): 

http://www.fngtps.com/passenger-preference-pane

Hint – just use:

$ gem install passenger

$ passenger-install-apache2-module

Leveraging browser caching

Here’s how to cache CSS / PNG files.

1. Use Expires caching headers 

i.e. rather than Cache-Control – see:

https://developers.google.com/speed/docs/best-practices/caching?hl=sv#LeverageBrowserCaching

2. If you’re using Apache these are set in the httpd.conf file:

e.g.  

<IfModule mod_expires.c>

    ExpiresActive On

    ExpiresDefault “access plus 10 days”

    ExpiresByType text/css “access plus 1 week”

    ExpiresByType text/plain “access plus 1 month”

    ExpiresByType image/gif “access plus 1 month”

    ExpiresByType image/png “access plus 1 month”

    ExpiresByType image/jpeg “access plus 1 month”

    ExpiresByType application/x-javascript “access plus 1 month”

    ExpiresByType application/javascript “access plus 1 week”

    ExpiresByType application/x-icon “access plus 1 year”

</IfModule>

http://css-tricks.com/snippets/htaccess/set-expires/

3. If you’re on a Dreamhost VPS the httpd.conf file is here:

/dh/apache2/apache2-ps<your-number>/etc/httpd.conf

To access it use:

su – <your-admin-user>

and restart with:

sudo /etc/init.d/httpd2 restart

4. And you can test how successful your updates were here:

http://tools.pingdom.com/fpt/

Using Capistrano to deploy your Rails app

1. if you haven’t got Rails installed locally then do it now. 

As of this blog post Rails 4, which you should be using, is pre-release so: 

gem install rails –pre

but drop the –pre when Rails 4 is no longer pre-release.

–pre means install the prerelease rails gem.

http://stackoverflow.com/questions/4041902/what-does-pre-do-in-gem-install-rails-pre

2. create a simple Rails app

rails new myapp

3. upload your Rails app to github

– create a git rep locally if it doesn’t exist

git init; git add .; git commit -am “first commit”

– create a github repo at 

https://github.com/new 

This should tell you what you need to do next however in short:

git remote add origin git@github.com:you/your_repo.git

git push -u origin master

4. capify with

capify .

(and remember to push to git with:

git add .; git commit -am “with capistrano”

git push -u origin master)

Note: as you’re running Rails you should put your Capistrano config information in config/deploy.rb. So, your Capfile should look like this:

load ‘config/deploy’

and your config/deploy.rb file should have all the Capfile details like 

set :git_username, “your_git_username”

set :repository,  “git@github.com:you/your_repo.git”

etc…

5. Use SSH agent forwarding initially

https://help.github.com/articles/managing-deploy-keys

Specifically, make sure you’ve got it set right locally:

https://help.github.com/articles/using-ssh-agent-forwarding

6. Read also this post if you’re having problems with your ssh key:

e.g. 

default_run_options[:pty] = true

helps debug. And add your host to your known_hosts file by doing ssh git@github.com and entering yes (it doesn’t matter that the login won’t succeed).

http://stackoverflow.com/questions/7863070/capistrano-deploy-host-key-verification-failed

and

https://help.github.com/articles/deploying-with-capistrano

7. Then use:

cap deploy:setup 

and

cap deploy:cold

For more details of what deploy:cold does see:

https://github.com/capistrano/capistrano/blob/master/lib/capistrano/recipes/deploy.rb#L200-L203

Notes

Some issues:

I found Capistrano wasn’t creating directories in the releases directory with this option:

set :deploy_via, :remote_cache

http://stackoverflow.com/questions/8246007/capistrano-will-not-create-releases

Also:

To automatically run ‘bundle install’ on the server, add this to your deploy.rb file:

require ‘bundler/capistrano’

http://gembundler.com/v1.3/deploying.html

8. If using a Dreamhost VPS you may need to unset the DreamHost Managed Apache setting in VPS > Configure Server.

http://wiki.dreamhost.com/VPS#httpd.conf

More on deploying Rails including details on Passenger (aka mod_rails), JRuby, Capistrano and Hosting:

http://rubyonrails.org/deploy