Securing PostgreSQL

Install PostgreSQL

sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

Upon installation, Postgres creates a Linux user called “postgres” which can be used to access the system. We can change to this user by typing:

sudo su - postgres

From here, we can connect to the system by typing:

psql

Notice how we can connect without a password. This is because Postgres has authenticated by username, which it assumes is secured.

Exit out of PostgreSQL and the postgres user by typing the following:

\q
exit

Disable Remote Connections

sudo vi /etc/postgresql/9.1/main/pg_hba.conf

Ensure the contents of the config file look something like the following:

local   all             postgres                                peer
local   all             all                                     peer
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5

The first two security lines specify “local” as the scope that they apply to. This means they are using Unix/Linux domain sockets.
The second two declarations are remote, but the hosts that they apply to (127.0.0.1/32 and ::1/128) are interfaces that specify the local machine.


What If You Need To Access the Databases Remotely?

To access PostgreSQL from a remote location, consider using SSH to connect to the database machine and then using a local connection to the database from there.
It is also possible to tunnel access to PostgreSQL through SSH so that the client machine can connect to the remote database as if it were local. Visit the PostgreSQL official documentation pages.

Use roles to lock down access to individual databases

Log into PostgreSQL:

sudo su - postgres
psql

To create a new role, type the following:

CREATE ROLE role_name WITH optional_permissions;

To see the permissions you can assign, type:

\h CREATE ROLE

You can alter the permissions of any role by typing:

ALTER ROLE role_name WITH optional_permissions;

List the current roles and their attributes by typing:

\du
List of roles
Role name |                   Attributes                   | Member of
-----------+------------------------------------------------+-----------
hello     | Create DB                                      | {}
postgres  | Superuser, Create role, Create DB, Replication | {}
testuser  |                                                | {}

Create a new user and assign appropriate permissions for every new application that will be using PostgreSQL.

Renewing letsencrypt certs for Apache

To renew as standalone and restart apache

sudo service apache2 stop
sudo certbot certonly –standalone

Saving debug log to /home/peter/appdir/~/.certbot/logs/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): staging.spxtrader.com.au
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for staging.spxtrader.com.au
Waiting for verification...
Cleaning up challenges
Non-standard path(s), might not work with crontab installed by your operating system package manager
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/home/peter/appdir/~/.certbot/config/live/staging.spxtrader.com.au/fullchain.pem
Your key file has been saved at:
/home/peter/appdir/~/.certbot/config/live/staging.spxtrader.com.au/privkey.pem
Your cert will expire on 2020-01-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

Then update your /etc/apache2/sites-available/vhosts-ssl.conf

sudo service apache2 start

TMUX Operations

Tmux cheat sheet

(C-x means ctrl+x, M-x means alt+x)
Prefix key

The default prefix is C-b. If you (or your muscle memory) prefer C-a, you need to add this to ~/.tmux.conf:

Remap prefix to Control + a

set -g prefix C-a

Bind ‘C-a C-a’ to type ‘C-a’

bind C-a send-prefix
unbind C-b

I’m going to assume that C-a is your prefix.

Sessions, Windows and Panes
Session is a set of windows, plus a notion of which window is current.
Window is a single screen covered with panes. (Once might compare it to a ‘virtual desktop’ or a ‘space’.)
Pane is a rectangular part of a window that runs a specific command, e.g. a shell.
Getting help

Display a list of keyboard shortcuts:

C-a ?

Navigate using Vim or Emacs shortcuts, depending on the value of mode-keys. Emacs is the default, and if you want Vim shortcuts for help and copy modes (e.g. j, k, C-u, C-d), add the following line to ~/.tmux.conf:

setw -g mode-keys vi

Any command mentioned in this list can be executed as tmux something or C-a :something (or added to ~/.tmux.conf).
Managing sessions

Creating a session:

tmux new -s work

Create a new session that shares all windows with an existing session, but has its own separate notion of which window is current:

tmux new-session -s work2 -t work

Attach to a session:

tmux attach -t work

Detach from a session:

C-a d.

Switch between sessions:

C-a (          previous session
C-a )          next session
C-a L          ‘last’ (previously used) session
C-a s          choose a session from a list

Other:

C-a $          rename the current session
C-a

Managing windows

Create a window:

C-a c          create a new window

Switch between windows:

C-a 1 ...      switch to window 1, ..., 9, 0
C-a 9
C-a 0
C-a p          previous window
C-a n          next window
C-a l          ‘last’ (previously used) window
C-a w          choose window from a list

Switch between windows with a twist:

C-a M-n        next window with a bell, activity or
content alert
C-a M-p        previous such window

Other:

C-a ,          rename the current window
C-a &          kill the current window

Managing split panes

Creating a new pane by splitting an existing one:

C-a "          split vertically (top/bottom)
C-a %          split horizontally (left/right)

Switching between panes:

C-a left       go to the next pane on the left
C-a right      (or one of these other directions)
C-a up
C-a down
C-a o          go to the next pane (cycle through all of them)
C-a ;          go to the ‘last’ (previously used) pane

Moving panes around:

C-a {          move the current pane to the previous position
C-a }          move the current pane to the next position
C-a C-o        rotate window ‘up’ (i.e. move all panes)
C-a M-o        rotate window ‘down’
C-a !          move the current pane into a new separate
window (‘break pane’)
C-a :move-pane -t :3.2
split window 3's pane 2 and move the current pane there

Resizing panes:

C-a M-up, C-a M-down, C-a M-left, C-a M-right
resize by 5 rows/columns
C-a C-up, C-a C-down, C-a C-left, C-a C-right
resize by 1 row/column

Applying predefined layouts:

C-a M-1        switch to even-horizontal layout
C-a M-2        switch to even-vertical layout
C-a M-3        switch to main-horizontal layout
C-a M-4        switch to main-vertical layout
C-a M-5        switch to tiled layout
C-a space      switch to the next layout

Other:

C-a x          kill the current pane
C-a q          display pane numbers for a short while

Other config file settings

Force a reload of the config file on C-a r:

unbind r
bind r source-file ~/.tmux.conf

Some other settings that I use:

setw -g xterm-keys on

If you have vi style key bindings on then the following applies:
1) enter copy mode using Control+b [

2) navigate to beginning of text, you want to select and hit Space

3) move around using arrow keys to select region

4) when you reach end of region simply hit Enter to copy the region

5) now Control+b ] will paste the selection
To enable vi like cursor movement in copy mode put the following in your ~/.tmux.conf:

set-window-option -g mode-keys vi

more over what ever you copy, you may dump that out in your terminal using

tmux show-buffer

and even save to a file(say, foo.txt) using

tmux save-buffer foo.txt

To see all the paste buffers try Control + b #. To dump out the varios buffers on to the terminal or file you may use

tmux list-buffers
tmux show-buffer -b n
tmux save-buffer -b n foo.txt

where n is the index of the paste buffer.

The Ruby Memoirs

IMG_4686

Ruby passed away on 15th February 2017 at about 1:10PM. He was about 10 years old.

He arrived on our front door about 6 months after we moved in (2008) and stayed. We found his original owners but he wasn’t impressed when they called to collect him and he decided he wanted to stay. Ruby usually got his way.

Initially he was supposed to be the downstairs cat at night with Java staying on our bed. That didn’t last long. He’d scratch the carpet at our bedroom door, frighten Java and keep us awake. He soon got his way with that too.

He’d hop up on our bed and grab a little blanket between his teeth and proceed to hump one of our legs (usually mine). That would last 5-10 minutes. We always thought it really weird but accepted it as one of Ruby’s quirks. He’d then jump off and find another place to lie for the night.

Occasionally he’d jump up onto the bed during the night and curl up in a ball between us…or be a pain in the ass and lie directly on one side of the bed or the other. You wouldn’t know it till you turned over in the middle of the night and felt the weight between your legs. Many nights of awkward sleeping with careful leg movements were had.

On Saturday mornings he’d start playing with cables (iPhone/iPad chargers) at the side of the bed to encourage us to get up. Eileen would throw something at him and he’d run at full speed up the hallway, thereby creating more noise. He’d eventually win the battle of sleep over food. I’d often wonder why there was a pair of women’s knickers on my side of the bed.

He would drink from a running tap in the bathroom and when we weren’t around to run the tap, from a glass we left on the bathroom locker. You’d hear him lapping at the water in the middle of the night sometimes. For some reason he’d always need encouragement to jump up onto the bathroom locker. It was only a 3 ft jump but he’d always hesitate. I remember when he was drinking you’d see his main teeth protruding down the side of his gums. They were long and sharp.

He loved company and would do anything to stay in the same room as me or Eileen. He’d often come into the bathroom when I was having a shower just to keep me company.

Play time consisted of him hiding under things, having you poke your hand in and praying it would come back in one piece. He’d hide under a table cloth cover in the spare room and swipe at your hand with his paws. He’d occasionally grab it and sink teeth into it. You’d see a cat-face shaped table cloth protruding through the pain. There was also the toy on a string which he’d hold with his front paws and rip the shit out of with his hind paws. If that’s the way he caught his prey, theres no way anything would have survived. His hind paws were powerful.

He’d often sit at the bottom of the stairs in the evening, looking up and then looking at me “come on…let’s play”. He’d run up stairs and hide in a cupboard waiting for me to put my hand in the door. He’d swipe my hand as if it was a game of tag. “Do it again! do it again!”. He’d give up the game at some indeterminate point and run into the bathroom for a drink.

One time the neighbours came knocking on our door to say Ruby was in the middle of the road stopping traffic. They were right, he refused to move for a car that had been forced to stop just in front of him. He only did that once. He would sit in the middle of the road in clear view of the neighbours dog. Teasing and causing a ruckus.

In the mornings he wanted to get out as soon as we were up (after a feed). He’d scarper out the cat flap to go hunting whatever was in the garden.

On occasion he’d wait for me to leave the house in the morning and follow me down to the corner of the street. No amount of ‘Ruby Go Home!’ would seem to work. If he didn’t go as far as the corner he’d stop at a sapling on the front verge and claw it as if to say “look at me…look at the fierce power I have over this tree”.

In the evenings, he’d be waiting outside the front of the house watching the corner of the street for me or Eileen to come home.

In the evenings he had a choice of beds but I don’t think he was ever happier than when he’d fall asleep in a big purple or brown round bed. You could approach him, give him a big hug or a tummy rub and get a tiny little whimper of contentment out of him. You had to be careful and choose your moments because he could easily get it in his head to engage your hand with his claws and not let you go. I developed good judgement skills as to his temperament and could usually tell when to pull my hand away.

I can’t count the numerous nights where he wouldn’t come in for hours in spite of me and Eileen going out to the road and calling him. We’d whistle and call “Ruby Ruby Ruby” until it was time for us to go to bed. He’d often surprise me by coming up behind as if he was there all the time. Other times we’d have to pick him up and carry him in as he struggled to break free from our arms. I was always relieved when we got him in before bed and I couldn’t sleep if he didn’t. I would come down later in the night to check if he had come in.

When Ruby arrived on the scene, there was a bucket load of pain for Java. They didn’t take to each other over at all. I thought it would take time but was very wrong. There was never a hint of peace between them. Java got to say goodbye to Ruby on the Monday before I took him down to the vet. She obviously didn’t know it was the last time she’d see him. And I didn’t know it was the last time I’d hold him.

He was often the cause of fights with poor Java who really had a tough time of it with him. I would run after him post fight looking for things to throw at him. He’d always come back a half hour later as if nothing had happened. And yes, he’d be forgiven. He’d start fights for no good reason other than Java was within reach.

There was the Saturday morning when he attacked Java and drew blood. She was limping and dripping blood all over the kitchen floor. I brought Java to the vet for mending ($105). I came home and Eileen was mopping up the blood with the sliding doors pulled open to let the floor dry. I saw java out the back licking her wounds and Ruby about to make a run at her. I shouted and started running at him. Eileen had subsequently closed the sliding glass door. I didn’t know until I’d gone through it. It was a galaxy of glass in the back garden. Eileen and I had a verbal and she left me cleaning up the mess. Thanks for the memories Ruby!

The peeing issue started soon after Ruby came along. It was a combination of both cats. We witnessed Ruby turning his back to couches, walls, cabinets and firing on all cylinders. The smell became intolerable. There were threats to get rid of him from all and sundry. Java wasn’t much better and made the most of opportunities to pee when she needed to mark her territory. We ended up getting rid of carpet and putting down washable floor surfaces. We sprayed smelly stuff here, there and everywhere. We got a bloody animal behaviouralist ($500). We were desperate to reach some sort of stable middle ground with both cats.

I guess, over time something worked out. For the last year or two there were very few peeing episodes. I can’t remember the last time we came home of an evening and had the sweet urinal aroma greet us.

He’d love dark places to hide and sleep. If he saw you laying out a rug with a nook for him to crawl into he’d be in his element. You could pet his ears as soon as he’d gone into it and you’d get another little whimper of joy. He was really happy there.

Sitting on the back garden table on a Saturday morning watching Eileen and I have breakfast with both paws extended like a Sphinx; waiting for something off our plate.

A liking for cheese, not just any cheese; usually cheddar or edam.

Waiting for Eileen to serve dinner and jumping up on the coffee table beside her looking for offerings.

I know there was a time before Ruby, but right now it feels like there is only a time with Ruby and after. The latter is sad and empty.

Smoothing out your workflow with git, github, RoR and Capistrano

Overview

Scripts can be found on github https://github.com/Peter-Mac/git_scripts

I use git, github and the Ruby on Rails capistrano gem to help manage my workflow.

The scripts contained here are handy one liners that help speed up my workflow so I dont really have to think too hard when I’m doing something that’s repetitive.

My Workflow

I do all of my development on feature branches that are then merged back to the ‘develop’ branch.

The develop branch is used to collate work from multiple devs before pushing to the ‘master’ branch.

The master branch is then used to push code for release to either a staging server or a production server.

Capistrano is used to connect to each server and act as the deployment mechanism. This way I can deploy to remote servers, watch the script working its way through the full code and database migration process.

The scripts

do_feature_merge.sh

This script allows you to

  • merge your current feature branch back into the ‘develop’ branch

  • provide a merge comment

  • create a new feature branch, or stay with the develop branch as active

do_release.sh

This script is used to push your local changes to the remote github repository and to provide a comment for the changes.

do_deploy.sh

This is the script responsible for executing the capistrano deployment tasks. It takes an environment value as parameter (either ‘staging’ or ‘production’).

  • It updates a VERSION file with the date and time of this release, checks the VERSION file into github,

  • It starts the capistrano deployment tasks

  • It checks out the develop branch ready for you to create your next feature branch

Joomla out of memory error with exception.php

I’ve just suffered a strange out of memory exception with one of my Joomla sites. All the posts I read indicated that I needed to allocate more memory in my php configuration – crazy I thought – I already had 64MB allocated. There must be something more fundamentally wrong for this nasty gremlin to be happening. The actual error is–


Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 40 bytes) in /home/site/public_html/libraries/joomla/error/exception.php on line 117

What I did (thanks to a couple of fragmented suggestions is change the line on 117 to the following


$this->backtrace = debug_print_backtrace();

Then re-render the site and you should see your browser fill with tons of crap. Hit the stop button after a second or two (before your browser crashes) and you should be able to see the root cause of your issue. For me it was a corruption of my jos_session table which I was able to fix with a truncate jos_session; command from the mysql command line.

I hope this note may save someone else a couple of hours of messing around with their memory settings.

Using magic_quotes_gpc or addslashes()

I’ve worked on a bundle of web based applications over the years and time and time again I’ve seen the recurring problem of the slash. Yes, we’ve probably all seen it in one or more forums where the apostrophe some user entered, probably with the name O’Brein ends up as O\Brein.

Why does this happen in sites running on PHP? The answer is a duplication of escapes. Yep, a Houdini Supreme.

Firstly a systems administrator has installed PHP and set the value for magic_quotes_gpc = on in the system’s php.ini (usually located in /etc/). This will automatically add slashes to all GET/POST/COOKIE data. This makes it safe before writing it to a database. Mr O’Brein becomes Mr O\’Brein when magic_quotes_gpc is set to on.

Secondly, a programmer has come along and thinking they’re doing the right thing takes all user input and uses the addslashes() funtion to escape all quotes. This results in a doubling of the escapes so, Mr O’\Brien now becomes MR O\\’Brein.

When this data is rendered, we see the automatic removal of only one set of escapes but the other set is left behind…yuck!!

When programmers see this they think “I’ll just use the stripslashes() method, I mean, that’s what it’s there for”. As the light from the idea bulb fades, they realise they’re fixing a problem that should never have occurred in the first place. You need to go to the source of your data and clean it up, make sure you’re either using magic_quotes_gpc=on OR addslashes. My preference is to use addslashes all the time and turn magic_quotes_gpc off, this way the logic of your code explicitly sets user input to be what you want.

Seeding your rails database

I’ve been working on a project that requires a good deal of test data to verify functionality. It involves train timetables with many lines, trains, stations etc. To help in uploading data for testing and development I’ve been using the rake db:seed command.


rake db:seed RAILS_ENV=development

or


rake db:seed RAILS_ENV=test

For the record I’m using a postgresql database but the use of the seeding implementation is database neutral. It will use the contents of the config/database.yml file to connect to whatever target environment you specify.

One of the problems with loading seed data is when dependencies exist between tables. You need to be able to identify records from table A to be able to create appropriate joins in table B. From a testing perspective there’s fixtures and factories. All well and good and each serves its’ purpose adequately. I wanted to build up a file that can be used to populate a database from scratch with the ability to add new records as your table set grows. I was also able to use it to sanity check my data model and joins as the project continued.

Here’s how the seeding works.

The relevant file is the seeds.rb file in your db folder.

To create single records you won’t need to refer to later in the seeding process, use something like this.


#firstly delete any existing data
User.delete_all
#now build up an array
users = [
  {email:'super@test.com', password:'@dmin123', password_confirmation: '@dmin123', admin:true, confirmed_at: '01/01/2011'},
  {email:'user@test.com', password:'user123', password_confirmation: 'user123', confirmed_at: '01/01/2011' }
]

#now process the array using an iterator
users.each { |user| User.create user }

To create rows to which you can refer to later on (such as when establishing a table join).


Line.delete_all

@frankston_direct_line=Line.create({name:'Frankston Direct'})
@frankston_loop_line=Line.create({name:'Frankston Loop'})
@sandringham_line=Line.create({name:'Sandringham'})

You can now refer to id of these records using the syntax @sandringham_line.id

So now I create a few train stations…


Station.delete_all

@aircraft=Station.create(name:'Aircraft' ,latitude:-37.866689 ,longitude:144.760795)
@alamein=Station.create(name:'Alamein' ,latitude: -37.86862  ,longitude: 145.08002)
@altona=Station.create(name:'Altona' ,latitude:-37.867231 ,longitude: 144.829609)
@armadale=Station.create(name:'Armadale', latitude:-37.85544, longitude: 145.018802)

#...
#list cut short for brevity

Now I create the association between the lines and stations

LineStation.delete_all


sandringham_line_stations = [
  { line_id: @sandringham_line.id, station_id: @parliament.id, ordinal:1, time:0},
  { line_id: @sandringham_line.id, station_id: @melbourne_central.id, ordinal:2, time:2},
  { line_id: @sandringham_line.id, station_id: @southern_cross.id, ordinal:3, time:3},
  { line_id: @sandringham_line.id, station_id: @flinders_arrival.id, ordinal:4, time:4},

  #...
  #list cut short for brevity
]

#now create all the LineStations iterating over the array
sandringham_line_stations.each { |linestation| LineStation.create linestation }

So there you have it. The ability to apply full referential integrity at database seeding time using the power of db:seed.

Rails background tasks with Rufus Scheduler

I have a database that is populated based on events that happen in real-time. I wanted to view the output of reports from that database on a regular basis (every 30 seconds). I found a lovely little gem called ‘rufus-scheduler’ that does the trick nice and neatly. Here’s how it worked for me.

Add the gem to your Gemfile


gem 'rufus-scheduler'

Update your bundle with bundle install


/path/to/my/app/$ bundle install

Create a file in your initializers folder. I’ve called mine task_scheduler. This file contains instructions to start the scheduled background process and on the tasks you want to run regularly.

The contents of mine are as follows:


scheduler = Rufus::Scheduler.start_new

scheduler.every("30s") do
   stats_direct = Stats.new("Frankston Direct")
   stats_direct.line_status

   stats_loop = Stats.new("Frankston Loop")
   stats_loop.line_status

   stats_loop = Stats.new("Sandringham")
   stats_loop.line_status
end

And that’s all there is to it.

More info on the gem can be found here

Capistrano Without Root Privileges

Given a user with sudo (but not root) access on a remote box, the following deploy.rb script will perform a capistrano deploy of a ruby application:

Assumptions:

  1. You’re using ‘git’. Although svn can be used, the script targets a git setup.

  2. You’re using mongrel_cluster. Change the script accordingly if using passenger etc.

  3. The application being deployed is dropped into a subfolder/subdirectory on the remote server. You can remove the task :recreate_public_link if you’re deploying to the root of a virtual directory.

  4. A user and group called ‘mongrel’ has been created on the remote server. This owns the running mongrel_cluster processes. Relevant permissions are set by the script.

    
    
    #-----------------------------------------------------
    # deploy.rb - controls deployment setup/configuration
    # using the capistrano or 'cap' deployment utility.
    #-----------------------------------------------------

    requires mongrel_cluster recipes to allow restart of mongrel cluster
    require 'mongrel_cluster/recipes'

    set :application, "[application name]"
    set :user, "peter"
    set :web_user, "apache"
    set :location, "[ip address]"
    #If you are using Passenger mod_rails uncomment the following block:
    #if you're still using the script/reapear helper you will need these
    # http://github.com/rails/irs_process_scripts

    namespace :deploy do

    task :start do ; end
    task :stop do ; end

    task :restart, :roles => :app, :except => { :no_release => true } do
        run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
    end
    end

    ssh_options[:forward_agent] = true

    default_run_options[:pty] = true
    set :scm, "git"
    set :scm_user, "git"
    set :repository, "#{scm_user}@#{location}:/usr/local/share/gitrepos/#{application}.git"
    set :scm_passphrase, "your password" #This is your custom users password
    set :git_shallow_clone, 1
    set :deploy_via, :remote_cache
    set :branch, "master"
    set :use_sudo, true
    set :site_root, "app/[application name]"
    role :app, location
    role :web, location
    role :db, location, :primary=>true
    set :deploy_to, "/var/www/html/[your test site url]/#{application}"
    #--------------

    mongrel details

    #--------------

    set :mongrel_conf, "#{deploy_to}/current/config/mongrel_cluster.yml"
    set :mongrel_user, "mongrel"
    set :mongrel_group, "mongrel"
    set :runner, nil
    set :mongrel_clean, true # helps keep mongrel pid files clean

    #----------------------

    migration parameters

    #---------------------

    set :rake, "rake"
    set :rails_env, "production"
    set :migrate_env, ""
    set :migrate_target, :latest

    before "deploy:update_code", "custom:set_permissions_for_checkout"
    before "deploy:migrate", "custom:set_permissions_pre_schema_dump"
    after "deploy:migrate", "custom:set_permissions_post_schema_dump"

    before "deploy:migrations", "custom:set_permissions_pre_schema_dump"
    after "deploy:migrations", "custom:set_permissions_post_schema_dump", "deploy:cleanup"
    before "deploy:symlink", "custom:get_current_ownership"

    after "deploy:symlink", "custom:update_application_controller",
    "custom:yield_current_ownership",
    "custom:set_permissions_for_runtime",
    "custom:recreate_public_link"

    namespace(:deploy) do
        desc "Restart the Mongrel processes on the app server."
        task :restart, :roles => :app do
            mongrel.cluster.stop
            sleep 2.5
            mongrel.cluster.start
        end
    end

    namespace(:custom) do
    desc "Change ownership of target folders and files to current user"
    task :set_permissions_for_checkout, :except => { :no_release => true } do
        chown of files to current user
        sudo "chown -R #{scm_user}:#{scm_user} #{deploy_to}"
    end

    desc "Change ownership of target folders and files to current user"
    task :set_permissions_for_runtime, :except => { :no_release => true } do
        chown of files to current user
        sudo "chown -R #{web_user}:#{web_user} #{deploy_to}"
        sudo "chown #{mongrel_user}.#{mongrel_group} -R #{deploy_to}/current/tmp/pids"
        sudo "chown #{mongrel_user}.#{mongrel_group} -R #{deploy_to}/current/log"
        sudo "chown #{mongrel_user}.#{mongrel_group} -R #{shared_path}/pids"
    end

    desc "Recreate link to serve public folders when hosting within subfolder"
    task :recreate_public_link do
        run <<-CMD
            cd #{deploy_to}/current/public && sudo ln -s . #{application}
        CMD
    end

    desc "Take temporary ownership of current folder to allow symlink updates"
    task :get_current_ownership do
        sudo "chown #{user}:#{user} #{release_path}"
    end

    desc "Take temporary ownership of current folder to allow symlink updates"
    task :yield_current_ownership do
        sudo "chown -R #{web_user}:#{web_user} #{release_path}"
    end

    desc "Change ownership of db folders and files to current user"
    task :set_permissions_pre_schema_dump, :except => { :no_release => true } do
        chown of files to current user
        sudo "chown -R #{user}:#{user} #{release_path}/db"
    end

    desc "Change ownership of db folders and files to current user"
    task :set_permissions_post_schema_dump, :except => { :no_release => true } do
        chown of files to current user
        sudo "chown -R #{web_user}:#{web_user} #{release_path}/db"
    end

    desc "Update application.rb to application_controller.rb"
    task :update_application_controller, :roles => :app do
        run <<-CMD
            cd #{deploy_to}/current/ && sudo rake rails:update:application_controller
        CMD
    end

    task :config, :roles => :app do
        run <<-CMD
            sudo ln -nfs #{shared_path}/system/database.yml #{release_path}/config/database.yml
        CMD
    end

    desc "Creating symbolic link (custom namespace)"
    task :symlink, :roles => :app do
        run <<-CMD
            sudo ln -nfs #{shared_path}/system/uploads #{release_path}/public/uploads
        CMD
    end
    end