diff --git a/src/api/encryption_get.c b/src/api/encryption_get.c
index cc64e6c214514d323a2befa0d0ac33e37da1ee42..6ae099df4f212e42a4d51a98f0bca1a319ec0087 100644
--- a/src/api/encryption_get.c
+++ b/src/api/encryption_get.c
@@ -29,7 +29,7 @@ int callback_encryption_get(const struct _u_request * request,
         can_encrypt_nullable = &can_encrypt;
 
         // Mount the filesystem on the unencrypted device.
-        int r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_MOUNTPOINT,
+        int r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_TMP_MOUNTPOINT,
             FILESYSTEM_TYPE);
         if (r != 0)
         {
@@ -37,9 +37,9 @@ int callback_encryption_get(const struct _u_request * request,
             return send_simple_response(response, 500, "error",
                "mounting root device failed");
         }
-        bool fits = filesystem_fits_in_memory(UNENCRYPTED_MOUNTPOINT,
+        bool fits = filesystem_fits_in_memory(UNENCRYPTED_TMP_MOUNTPOINT,
             MEMORY_USAGE);
-        umount(UNENCRYPTED_MOUNTPOINT);
+        umount(UNENCRYPTED_TMP_MOUNTPOINT);
         if (! fits)
         {
             can_encrypt = false;
diff --git a/src/api/encryption_init_post.c b/src/api/encryption_init_post.c
index 14d6742dc34a04fdc104cd80352ef30b09840bd8..aeef25d1a835ff05c8e3cda53527521707ff8073 100644
--- a/src/api/encryption_init_post.c
+++ b/src/api/encryption_init_post.c
@@ -53,7 +53,7 @@ int callback_encryption_init_post(const struct _u_request * request,
     }
 
     // Mount the filesystem on the unencrypted device.
-    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_MOUNTPOINT,
+    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -62,8 +62,8 @@ int callback_encryption_init_post(const struct _u_request * request,
            "mounting root device failed");
     }
 
-    // Determine the filesystem usage of the device to be encrypted.
-    bool fits = filesystem_fits_in_memory(UNENCRYPTED_MOUNTPOINT,
+    // Determine if the files on the unencrypted device would fit in memory.
+    bool fits = filesystem_fits_in_memory(UNENCRYPTED_TMP_MOUNTPOINT,
         MEMORY_USAGE);
     if (! fits)
     {
@@ -75,7 +75,8 @@ int callback_encryption_init_post(const struct _u_request * request,
     // Copy device contents to temporary filesystem.
     printf("copying existing root device contents to memory\n");
     char * command = NULL;
-    asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_MOUNTPOINT, TMP_LOCATION);
+    asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_TMP_MOUNTPOINT,
+        TMP_LOCATION);
     r = system(command);
     if(r != 0)
     {
@@ -86,8 +87,8 @@ int callback_encryption_init_post(const struct _u_request * request,
     }
 
     // Unmount unencrypted device.
-    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_MOUNTPOINT);
-    r = umount(UNENCRYPTED_MOUNTPOINT);
+    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_TMP_MOUNTPOINT);
+    r = umount(UNENCRYPTED_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting encrypted device failed: return code %d\n", r);
@@ -153,7 +154,7 @@ int callback_encryption_init_post(const struct _u_request * request,
 
     // Mount the info partition.
     printf("mounting info partition\n");
-    r = temporary_mount(INFO_PARTITION_DEVICE, INFO_MOUNTPOINT,
+    r = temporary_mount(INFO_PARTITION_DEVICE, INFO_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -165,8 +166,8 @@ int callback_encryption_init_post(const struct _u_request * request,
     // Create some directories in the info partition.
     printf("creating directories in info partition\n");
     command = NULL;
-    asprintf(&command, "mkdir -p %s%s %s%s", INFO_MOUNTPOINT,
-        AUTHORIZED_KEYS_DIR, INFO_MOUNTPOINT, SSH_HOST_KEY_DIR);
+    asprintf(&command, "mkdir -p %s%s %s%s", INFO_TMP_MOUNTPOINT,
+        AUTHORIZED_KEYS_DIR, INFO_TMP_MOUNTPOINT, SSH_HOST_KEY_DIR);
     r = system(command);
     if (r != 0)
     {
@@ -179,7 +180,7 @@ int callback_encryption_init_post(const struct _u_request * request,
     printf("copying authorized_keys to info partition\n");
     command = NULL;
     asprintf(&command, "cp %s %s%s",
-        AUTHORIZED_KEYS_PATH, INFO_MOUNTPOINT, AUTHORIZED_KEYS_PATH);
+        AUTHORIZED_KEYS_PATH, INFO_TMP_MOUNTPOINT, AUTHORIZED_KEYS_PATH);
     r = system(command);
     if (r != 0)
     {
@@ -191,7 +192,7 @@ int callback_encryption_init_post(const struct _u_request * request,
     // Copy dropbear ssh host keys from the initrd to the info partition.
     printf("copying dropbear ssh host keys\n");
     command = NULL;
-    asprintf(&command, "cp /etc/dropbear/* %s%s/", INFO_MOUNTPOINT,
+    asprintf(&command, "cp /etc/dropbear/* %s%s/", INFO_TMP_MOUNTPOINT,
         SSH_HOST_KEY_DIR);
     r = system(command);
     if (r != 0)
@@ -202,8 +203,8 @@ int callback_encryption_init_post(const struct _u_request * request,
     }
 
     // Unmount info partition.
-    printf("unmounting info partition at %s\n", INFO_MOUNTPOINT);
-    r = umount(INFO_MOUNTPOINT);
+    printf("unmounting info partition at %s\n", INFO_TMP_MOUNTPOINT);
+    r = umount(INFO_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting failed: return code %d\n", r);
@@ -246,7 +247,7 @@ int callback_encryption_init_post(const struct _u_request * request,
 
     // Mount the unlocked container.
     printf("mounting new filesystem\n");
-    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_MOUNTPOINT,
+    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -258,7 +259,7 @@ int callback_encryption_init_post(const struct _u_request * request,
     // Copy device contents from temporary filesystem to encrypted container.
     printf("copying root device contents from memory\n");
     command = NULL;
-    asprintf(&command, "rsync -a %s/ %s", TMP_LOCATION, DATA_MOUNTPOINT);
+    asprintf(&command, "rsync -a %s/ %s", TMP_LOCATION, DATA_TMP_MOUNTPOINT);
     r = system(command);
     if (r != 0)
     {
@@ -269,8 +270,8 @@ int callback_encryption_init_post(const struct _u_request * request,
     }
 
     // Unmount filesystem on encrypted data partition.
-    printf("unmounting encrypted device at %s\n", DATA_MOUNTPOINT);
-    r = umount(DATA_MOUNTPOINT);
+    printf("unmounting encrypted device at %s\n", DATA_TMP_MOUNTPOINT);
+    r = umount(DATA_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting encrypted device failed: return code %d\n", r);
diff --git a/src/api/encryption_remove_post.c b/src/api/encryption_remove_post.c
new file mode 100644
index 0000000000000000000000000000000000000000..452a223aee1e79d826eb76dd41cdd5202ff6df75
--- /dev/null
+++ b/src/api/encryption_remove_post.c
@@ -0,0 +1,194 @@
+/**
+ * Callback function for permanently decrypting an encrypted device.
+ * It proceeds as follows:
+ * 1.  read the encryption password from the request body;
+ * 2.  check if the device isn't already encrypted;
+ * 3.  unlock the encrypted container;
+ * 4.  mount the filesystem on the encrypted device;
+ * 5.  check if there is enough available memory to contain all files currently
+ *     stored on the device;
+ * 6.  copy device contents to temporary filesystem;
+ * 7.  unmount encrypted device;
+ * 8.  lock the container;
+ * 9.  unmount info partition;
+ * 10. remove all partitions from the device;
+ * 11. create a new filesystem on the unencrypted device;
+ * 12. mount the new filesystem;
+ * 13. copy device contents from memory to encrypted container;
+ * 14. unmount the new filesystem;
+ * 15. reboot.
+ * @param[in]   request   incoming HTTP request
+ * @param[out]  response  HTTP response to the request
+ * @param[in]   user_data extra data to pass between handler and main thread
+ * @return                internal status code
+ */
+int callback_encryption_remove_post(const struct _u_request * request,
+    struct _u_response * response, void * user_data)
+{
+    bool * reboot = (bool *)user_data;
+    int r;
+
+    // Read the encryption password from the request body.
+    json_t * json_input = ulfius_get_json_body_request(request, NULL);
+    const char * password = password = json_string_value(
+        json_object_get(json_input, "password"));
+    if (password == NULL)
+    {
+        return send_simple_response(response, 400, "error", "missing password");
+    }
+ 
+    // Check if the device is encrypted.
+    if (! is_encrypted_device(DATA_PARTITION_DEVICE))
+    {
+        // The device is not encrypted, so this command does not make sense.
+        return send_simple_response(response, 400, "error",
+           "not encrypted");
+    }
+
+    // Unlock the container.
+    printf("unlocking encrypted device\n");
+    r = encryption_unlock(DATA_PARTITION_DEVICE, MAPPED_DEVICE_NAME,
+        password);
+    if (r == -1)
+    {
+        // The return code -1 signals that the password is wrong.
+        return send_simple_response(response, 403, "error",
+           "incorrect password");
+    }
+    if (r != 0)
+    {
+        printf("unlocking encrypted container failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unlocking encrypted container failed");
+    }
+
+    // Mount the filesystem on the encrypted data partition.
+    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_TMP_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        printf("mounting root device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "mounting root device failed");
+    }
+
+    // Determine the filesystem usage of the encrypted data partition.
+    bool fits = filesystem_fits_in_memory(DATA_TMP_MOUNTPOINT, MEMORY_USAGE);
+    if (! fits)
+    {
+        // Projected memory usage is really high, so abort.
+        return send_simple_response(response, 500, "error",
+           "device too large");
+    }
+
+    // Copy device contents to temporary filesystem.
+    printf("copying existing root device contents to memory\n");
+    char * command = NULL;
+    asprintf(&command, "rsync -a %s/ %s", DATA_TMP_MOUNTPOINT, TMP_LOCATION);
+    r = system(command);
+    if(r != 0)
+    {
+        printf("copying root device contents into memory failed"
+            ": return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+            "copying root device contents into memory failed");
+    }
+
+    // Unmount encrypted data partition.
+    printf("unmounting encrypted device at %s\n", DATA_TMP_MOUNTPOINT);
+    r = umount(DATA_TMP_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting encrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting encrypted device failed");
+    }
+
+    // Lock the container.
+    printf("locking encrypted device\n");
+    r = encryption_lock(MAPPED_DEVICE_NAME);
+    if (r != 0)
+    {
+        printf("locking encrypted container failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "locking encrypted container failed");
+    }
+
+    // Unmount info partition.
+    // We didn't mount this in cryptops-api, but it was mounted by the initrd
+    // scripts for use by dropbear.
+    printf("unmounting info partition at %s\n", INFO_MOUNTPOINT);
+    r = umount(INFO_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting info partition failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting info partition failed");
+    }
+
+    // Remove all partitions from the device.
+    printf("removing partitions from device %s\n", ROOT_DEVICE);
+    command = NULL;
+    asprintf(&command, "sgdisk -Z %s", ROOT_DEVICE);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("removing partitions failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "removing partitions failed");
+    }
+
+    // Create filesystem on the unencrypted device.
+    printf("creating filesystem on unencrypted device\n");
+    command = NULL;
+    asprintf(&command, "mkfs -t %s %s", FILESYSTEM_TYPE, ROOT_DEVICE);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("creating filesystem failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "creating filesystem on unencrypted device failed");
+    }
+
+    // Mount the new filesystem.
+    printf("mounting new filesystem\n");
+    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_TMP_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        printf("mounting unencrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "mounting unencrypted root device failed");
+    }
+
+    // Copy device contents from memory to the unencrypted device.
+    printf("copying root device contents from memory\n");
+    command = NULL;
+    asprintf(&command, "rsync -a %s/ %s",
+        TMP_LOCATION, UNENCRYPTED_TMP_MOUNTPOINT);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("copying from memory to unencrypted device failed:"
+            " return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "copying root device contents from memory failed");
+    }
+
+    // Unmount filesystem on unencrypted device.
+    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_TMP_MOUNTPOINT);
+    r = umount(UNENCRYPTED_TMP_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting unencrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting unencrypted device failed");
+    }
+
+    // Record that we want to reboot the machine.
+    *reboot = true;
+
+    r = send_simple_response(response, 200, "status", "ok");
+    stop_server();
+    return r;
+}
diff --git a/src/cryptops-api.c b/src/cryptops-api.c
index 389f9934efe2da0b960bc0f43bced136bcba947a..114850423a3f74cb710a1a3edb661e0f6160b9d7 100644
--- a/src/cryptops-api.c
+++ b/src/cryptops-api.c
@@ -8,6 +8,7 @@
 #include <api/default.c>
 #include <api/encryption_get.c>
 #include <api/encryption_init_post.c>
+#include <api/encryption_remove_post.c>
 #include <api/encryption_unlock_post.c>
 #include <api/encryption_keys_put.c>
 #include <api/ssh_keys_get.c>
@@ -44,6 +45,9 @@ int main(int argc, char ** argv)
     ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
         "/encryption/init",
         0, &callback_encryption_init_post, &reboot);
+    ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
+        "/encryption/remove",
+        0, &callback_encryption_remove_post, &reboot);
     ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
         "/encryption/unlock",
         0, &callback_encryption_unlock_post, NULL);
@@ -97,6 +101,10 @@ int main(int argc, char ** argv)
         y_log_message(Y_LOG_LEVEL_DEBUG, "Error starting framework");
     }
     y_log_message(Y_LOG_LEVEL_DEBUG, "End framework");
+
+    // Give request handlers that have called for the stop a chance to
+    // send their response to the client.
+    sleep(1);
     
     y_close_logs();
     
diff --git a/src/includes/settings.h b/src/includes/settings.h
index 8352c51513477907acf8d2148e30fb6807203cbf..8035b1024dfa8b91d5fb4c76c4f878f682ad9266 100644
--- a/src/includes/settings.h
+++ b/src/includes/settings.h
@@ -1,17 +1,31 @@
+// Web interface settings.
 #define PREFIX "/cryptops/v0"
 #define PORT 8000
 #define BIND_ADDRESS "127.0.0.1"
+
+// Device paths.
 #define ROOT_DEVICE "/dev/xvda"
 #define INFO_PARTITION_DEVICE ROOT_DEVICE "1"
 #define DATA_PARTITION_DEVICE ROOT_DEVICE "2"
 #define MAPPED_DEVICE_NAME "xvda1_crypt"
 #define MAPPED_DEVICE_PATH "/dev/mapper/" MAPPED_DEVICE_NAME
+
+// Filesystem parameters.
 #define FILESYSTEM_TYPE "xfs"
+
+// Mountpoint paths.
+#define INFO_MOUNTPOINT "/conf/persistent"
+
+// Resource usage.
 #define MEMORY_USAGE 0.9
-#define UNENCRYPTED_MOUNTPOINT "/tmp/mnt-plain"
-#define INFO_MOUNTPOINT "/tmp/mnt-info"
-#define DATA_MOUNTPOINT "/tmp/mnt-data"
+
+// Temporary mountpoints.
+#define UNENCRYPTED_TMP_MOUNTPOINT "/tmp/mnt-plain"
+#define INFO_TMP_MOUNTPOINT "/tmp/mnt-info"
+#define DATA_TMP_MOUNTPOINT "/tmp/mnt-data"
 #define TMP_LOCATION "/tmp/" MAPPED_DEVICE_NAME
+
+// Ssh configuration file locations.
 #define AUTHORIZED_KEYS_DIR "/root/.ssh"
 #define AUTHORIZED_KEYS_PATH AUTHORIZED_KEYS_DIR "/authorized_keys"
-#define SSH_HOST_KEY_DIR "/dropbear"
\ No newline at end of file
+#define SSH_HOST_KEY_DIR "/dropbear"