diff --git a/hosting.drush.inc b/hosting.drush.inc
index 00bbedc..093c4d4 100644
--- a/hosting.drush.inc
+++ b/hosting.drush.inc
@@ -26,6 +26,13 @@ function hosting_drush_command() {
     'description' => 'execute a specific queue item',
     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL
   );
+
+  $items['hosting migrate'] = array('description' => 'migrate the frontend site', 'arguments' => array('example.com' => dt('The name of the site to migrate'), '/path/to/platform' => dt('The platform to migrate the site to.')));
+
+  $items['hosting park'] = array('description' => 'disable the frontend site prior to migration', 'arguments' => array('example.com' => dt('The name of the site to park')));
+
+  $items['hosting unpark'] = array('description' => 'enable the frontend site after a migration', 'arguments' => array('example.com' => dt('The name of the site to unpark')));
+
   return $items;
 }
 
diff --git a/hosting.inc b/hosting.inc
new file mode 100644
index 0000000..1050ac9
--- /dev/null
+++ b/hosting.inc
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ *
+ * General purpose functions
+ *
+ * Those functions are destined to be used by the frontend Drupal
+ * module as well as the drush hooks of the frontend
+ */
+
+/**
+ * Check if a hostname provided is an ip address
+ */
+function _hosting_valid_ip($hostname) {
+  //TODO : provide IPv6 support
+  $parts = explode('.', $hostname);
+  if (sizeof($parts) != 4) {
+    return false;
+  }
+  foreach ($parts as $part) {
+    if (((int) $part < 0) || ((int) $part > 255)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Check if the FQDN provided is valid.
+ */
+function _hosting_valid_fqdn($fqdn) {
+  # regex is an implementation of RFC1035
+  return preg_match("/^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.?)+$/i", $fqdn);
+}
+
+function hosting_format_interval($ts) {
+  if ($ts==mktime()) { 
+    return t('Now');
+  }
+  if (!$ts) {
+    //Treats EPOCH as never
+    return t('Never');
+  }
+
+  return t("@interval ago", array("@interval" => format_interval(mktime() - $ts, 1)));
+}
+
+/**
+ * Make a path canonical
+ *
+ * This removes duplicate slashes, trailing slashes and /./ occurences. It does
+ * not (yet?) resolve .. instances.
+ */
+function hosting_path_normalize($path) {
+  return rtrim(preg_replace('/(\/\/*\.)?\/\/*/', '/', $path), '/');
+}
diff --git a/migrate.hosting.inc b/migrate.hosting.inc
new file mode 100644
index 0000000..4232e83
--- /dev/null
+++ b/migrate.hosting.inc
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file manual site migrate system
+ */
+
+function drush_hosting_hosting_migrate_validate($site, $platform) {
+  // verify the target platform:
+  $data = drush_get_merged_options(); // XXX: necessary because the remote
+                                      // platform may not have been
+                                      // initialised by the frontend (this
+                                      // should be checked instead)
+  $data['root'] = $platform;
+  $data['r'] = $platform;
+  drush_backend_invoke('provision verify', $data);
+  // verify the current platform
+  drush_backend_invoke('provision verify', array('root' => drush_get_option(array('r', 'root'), drush_locate_root())));
+  // verify the site prior to migration
+  drush_backend_invoke('provision verify', array($site));
+}
+
+function drush_hosting_pre_hosting_migrate($site, $platform) {
+  return drush_backend_invoke('hosting park', array($site, $platform));
+}
+
+function drush_hosting_hosting_migrate($site, $platform) { 
+  return drush_backend_invoke('provision clone', array($site, $site, $platform));
+}
+
+function drush_hosting_hosting_migrate_rollback($site, $platform) {
+  return drush_backend_invoke('provision delete', array($site, 'root' => $platform));
+}
+
+function drush_hosting_post_hosting_migrate($site, $platform) {
+  drush_backend_invoke('hosting unpark', array($site, $platform));
+  if (!drush_get_error()) {
+    drush_backend_invoke('provision delete', array($site));
+    drush_backend_invoke('provision verify', array($site, 'root' => $platform, 'publish_path' => $platform));
+  }
+}
diff --git a/park.hosting.inc b/park.hosting.inc
new file mode 100644
index 0000000..4230171
--- /dev/null
+++ b/park.hosting.inc
@@ -0,0 +1,28 @@
+<?php
+
+include_once('hosting.inc');
+
+/**
+ * Make sure that AEgir is ready to be parked
+ *
+ * @todo make sure no task is running
+ */
+function drush_hosting_hosting_park_validate($url, $platform) {
+  if ($platform_id = db_result(db_query('SELECT nid FROM {hosting_platform} WHERE publish_path = "%s"', hosting_path_normalize($platform)))) {
+    drush_log(dt('Platform found for path %path: #%id', array('%path' => $platform, '%id' => $platform_id)));
+  }
+  else {
+    return drush_set_error('PROVISION_FRAMEWORK_ERROR', dt("Cannot find target platform at @path before parking site. Make sure the platform exists in the frontend first.", array('@path' => $platform)));
+  }
+}
+
+/**
+ * TODO: prepare the site for migration
+ * - disable the queue (variable_set...)
+ * - disable the cronjob
+ * - create a failed migrate task for logging
+ * - disable the site
+ */
+function drush_hosting_hosting_park($url) {
+  
+}
diff --git a/platform/hosting_platform.module b/platform/hosting_platform.module
index 1b1e28b..98e72c4 100644
--- a/platform/hosting_platform.module
+++ b/platform/hosting_platform.module
@@ -129,8 +129,6 @@ function hosting_platform_form(&$node) {
   return $form;
 }
 
-
-
 /**
  * Implementation of hook_insert().
  */
@@ -142,7 +140,7 @@ function hosting_platform_insert($node) {
     hosting_add_task($node->nid, 'verify');
   }
   db_query("INSERT INTO {hosting_platform} (vid, nid, publish_path, verified, web_server) VALUES (%d, %d, '%s', %d, %d)",
-    $node->vid, $node->nid, $node->publish_path, $node->verified, $node->web_server);
+    $node->vid, $node->nid, hosting_path_normalize($node->publish_path), $node->verified, $node->web_server);
 }
 
 /**
@@ -161,7 +159,7 @@ function hosting_platform_update($node) {
       variable_set('hosting_default_platform', $node->nid);
     }
     db_query("UPDATE {hosting_platform} SET publish_path = '%s', web_server = %d, verified = %d WHERE nid=%d",
-              $node->publish_path, $node->web_server, $node->verified, $node->nid);
+              hosting_path_normalize($node->publish_path), $node->web_server, $node->verified, $node->nid);
   }
 }
 
@@ -189,7 +187,7 @@ function hosting_platform_delete($node) {
  * Implementation of hook_validate()
  */
 function hosting_platform_validate($node, &$form) {
-  if ($node->op != t('Delete') && $result = db_fetch_object(db_query("SELECT n.title AS name FROM {hosting_platform} AS h INNER JOIN {node} AS n ON n.nid = h.nid WHERE publish_path = '%s' AND web_server = %d AND n.nid <> %d", $node->publish_path, $node->web_server, $node->nid))) {
+  if ($node->op != t('Delete') && $result = db_fetch_object(db_query("SELECT n.title AS name FROM {hosting_platform} AS h INNER JOIN {node} AS n ON n.nid = h.nid WHERE publish_path = '%s' AND web_server = %d AND n.nid <> %d", hosting_path_normalize($node->publish_path), $node->web_server, $node->nid))) {
     form_set_error('publish_path', t('Path already defined in platform %name', array('%name' => $result->name)));
   }
 }
diff --git a/unpark.hosting.inc b/unpark.hosting.inc
new file mode 100644
index 0000000..ee185ed
--- /dev/null
+++ b/unpark.hosting.inc
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file Implementation of the hosting unpark command
+ */
+
+include_once('hosting.inc');
+
+function drush_hosting_hosting_unpark($url, $platform) {
+  drush_log('bootstrapping drupal');
+  drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
+  drush_log('fixing platform');
+  if ($platform_id = db_result(db_query('SELECT nid FROM {hosting_platform} WHERE publish_path = "%s"', hosting_path_normalize($platform)))) {
+    $nid = db_result(db_query('SELECT nid FROM {node} WHERE type = "site" AND status = 1 AND title = "%s"', $url));
+    $node = node_load($nid);
+    $node->verified = 0;
+    $node->platform = $platform_id;
+    node_save($node);
+  } else {
+    return drush_set_error('PROVISION_FRAMEWORK_ERROR', dt("Could not find the node for platform path %platform", array('%platform' => $platform)));
+  }
+  // TODO: post migration tasks
+  // - turn on new cron job
+  // - save the drush log to the migrate task and set proper status
+}
