-
Notifications
You must be signed in to change notification settings - Fork 261
Deployment Guide
This guide covers how to setup the production environment for your BrowserCMS application. This setup should work for both:
- Apache (mod_rails) with Passenger
- Nginx with Passenger (though it's less well tested than Apache)
This guide is valid as of BrowserCMS 3.5.0.rc1.
In order for the CMS to send emails, you need to edit the following lines on production.rb:
# This should match the URL for your public CMS site.
config.cms.site_domain = "www.example.com"
# Configure your mail server host name
config.action_mailer.smtp_settings = {:address => 'mailserver.example.com', :domain => config.cms.site_domain}
In order to make page caching work, you need to create two virtual hosts for your site. The desired endstate is to end up with two top level domains. For example, assuming our domain is example.com
, we want to have the following domains when we are done:
-
www.example.com
- The 'public' access to the site, which is uses page caching for speed. -
cms.example.com
- The 'admin' access to the site, which allow editors to make changes.
Its a good idea to set up a redirect from example.com
to www.example.com
for ease of access and SEO purposes. The main reason to use www.example.com
as the 'canonical' domain rather then dropping the www is due to some browsers (IE) having issues with cookies on example.com
being visible to cms.example.com
. Admin users will have hard to diagnose problems when they are logged in.
Some hosting setups may not like subdomains (or are harder to setup). You can run the CMS off a single domain by setting the following:
# In production.rb
config.cms.use_single_domain = true
This will disable all page caching though, which has performance implications.
Here is the sample configuration for Apache plus Passenger.
<VirtualHost *:80>
ServerName cms.mysite.com
DocumentRoot "/var/sites/mysite/public"
RailsEnv production
<directory "/var/sites/mysite/public">
Order allow,deny
Allow from all
</directory>
</VirtualHost>
<VirtualHost *:80>
ServerName mysite.com
DocumentRoot "/var/sites/mysite/public"
RailsEnv production
RewriteEngine On
# Uncomment for rewrite debugging
#RewriteLog /var/sites/mysite/log/rewrite.log
#RewriteLogLevel 9
# Ensure we are not serving pages with trailing slashes
RewriteRule ^(.+)/$ $1 [R=301,L]
# Apache should serve cached pages
RewriteRule ^/$ /cache/index.html [QSA]
RewriteRule ^([^.]+)$ /cache/$1.html [QSA]
<directory "/var/sites/mysite/public">
Order allow,deny
Allow from all
</directory>
</VirtualHost>
Here is a sample configuration for Nginx.
server {
listen 80;
server_name cms.example.com
www.cms.example.com;
# remove 'www'
if ($host ~* ^www\.(.*)) {
set $remove_www $1;
rewrite ^(.*)$ http://$remove_www$1 permanent;
}
# point to public
root /home/example.com/www/public;
# if you use reverse proxy (in case of multiple rubies)
# point to your ip/port in location
# if you use only one ruby with passenger (for example REE) skip this location block
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
}
# passenger related stuff
passenger_enabled on;
}
server {
listen 80;
server_name example.com
www.example.com;
# remove 'www'
if ($host ~* ^www\.(.*)) {
set $remove_www $1;
rewrite ^(.*)$ http://$remove_www$1 permanent;
}
# Cache Index HTML Files
if (-f $document_root/cache/$uri/index.html) {
rewrite (.*) /cache/$1/index.html break;
}
# Cache HTML Files
if (-f $document_root/cache/$uri.html) {
rewrite (.*) /cache/$1.html break;
}
# Cache Catch all
if (-f $document_root/cache/$uri) {
rewrite (.*) /cache/$1 break;
}
# point to public
root /home/example.com/www/public;
# if you use reverse proxy (in case of multiple rubies)
# point to your ip/port in location
# if you use only one ruby with passenger (for example REE) skip this location block
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
}
# passenger related stuff
passenger_enabled on;
}
I believe there's a better way to do it. Main idea is to listen to domains and sub domains in one 'server' block, but if user comes from sub domain we should skip caching statements. Unfortunately nginx doesn't support multiple conditions neither nested "if's" to check whether request came from sub domain or not.
When you deploy your project to a remote server for the first time, you need to do migrate/populate the database on your production server. BrowserCMS provides a nice shortcut to setup your database in one go. After pushing your code's project, run:
rake db:install
Calling this task is essentially the same as calling rake db:create db:migrate db:seed
. Take note of the generated password for the cmsadmin user.
If you choose to copy a local database to your production server, make sure you change the default cmsadmin password to something non-guessable for security purposes.
If you plan to use Capistrano to deploy your sites, you will likely need to make some additional configuration changes.
The default location where files are stored is tmp/uploads, which means capistrano deployments will cause broken links after deploying. To fix this, you can reconfigure where files are stored to use a shared directory.
# In config/environments/production.rb
config.cms.attachments.storage_directory = File.join(Rails.root, 'uploads')
Then update config/deploy.rb (which Capistrano should generate) so that it creates an shared/uploads directory, and a symlink to it from within your project.
# In config/deploy.rb
task :link_shared_directories do
run "ln -s #{shared_path}/uploads #{release_path}/uploads"
end
after "deploy:update_code", :link_shared_directories
The binary data for uploaded files will be placed in shared/uploads and the CMS will serve the data from there.
One way to improve the performance of BrowserCMS is to enable X-Sendfile. Used in conjunction with Web servers like Apache and Nginx, X-Sendfile will allow web servers to handle serving files that have been uploaded into the CMS. Web servers are very well optimized for sending static files, and doing so takes load off the Ruby processes reducing bottlenecks.
To enable X-Sendfile in your application, uncomment one of the following two lines depending on which web server you are using.
# In config/environments/production.rb
config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
You will then need to configure your web server to handle X-Sendfile requests. See documentation for Apache and Nginx for details.
The Rails asset pipeline will need to be configured correctly so that assets can be compiled in production. There are two ways to handle assets:
- On the fly asset compilation
- Precompile assets
See http://guides.rubyonrails.org/asset_pipeline.html#in-production for some more details.
The easiest way to handle this (especially for testing) is to let assets be compiled on the server. Edit the following files:
# In config/environments/production.rb
# Setting this to true allows assets to be compiled as requested, rather than precompiled.
config.assets.compile = true
Next update the Gemfile
to allow for asset compilation on the server. therubyracer
is a JS runtime that may be needed to on some server environments which don't come with one preinstalled.
# In Gemfile
group :production do
gem 'uglifier'
gem 'therubyracer'
end
This option assumes you are using capistrano for deployment. Add the following to your config/deploy.rb:
set :rake, '/absolute/path/to/rake/on/server' # Figure this out by doing `which rake` on server
load 'deploy/assets'
Modify config/environments/production.rb to reflect the following (specifically these notes are for 3.5.x):
config.assets.precompile += %w( cms/core_library.js cms/taglist.css cms/date_picker.css cms/sitemap.css cms/page_toolbar.css cms/selectbox.css cms/content_library.js cms/dashboard.css cms/toolbar.js bcms/ckeditor_load.js cms/administration.css cms/login.css cms/form_layout.css cms/content_library.css ckeditor-jquery.js ckeditor_standard_config.js cms/block.css)
config.assets.initialize_on_precompile = false
config.assets.compile = false
The list of files to be precompiled is overly long for CMS v3.5.x and should be corrected in later versions.
If assets compilation is slow, considering using the Turbo Sprockets gem which avoid recompiling assets that didn't change. Follow the installation instructions for the gem.
If you run into permission errors during deploy, it may be related to file permissions that requires ownership of files to retimestamp them. Try adding the following to capistrano gem to take ownership of the assets directory.
namespace :deploy do
namespace :assets do
task :take_ownership do
run "ME=`whoami` && sudo chown -R $ME /path/to/assets/directory"
end
task :return_ownership do
run "sudo chown -R rightful_owner /path/to/assets/directory"
end
end
end
before "deploy:assets:precompile", "deploy:assets:take_ownership"
after "deploy:assets:precompile", "deploy:assets:return_ownership"
For Rails 3/bundler, you need to tell capistrano to run bundle install after deployment. See "Bundler's Docs":http://gembundler.com/rationale.html and "this post":http://blog.josephholsten.com/2010/09/deploying-with-bundler-and-capistrano/ for some ideas into how to do that. The most common setup will be something like this though:
# In config/deploy.rb
require "bundler/capistrano
# This may not be necessary, depending on your server setup.
# To see other options, run cap --explain bundle:install
set :bundle_cmd, '/opt/ruby-ee/bin/bundle'
In production, if you want to use the editable templates feature (Admin -> Templates), you will need to tell Rails not to cache views. Otherwise, changes to templates will not be picked up until you restart Passenger.
# In config/environments/production.rb
config.action_view.cache_template_loading = false