diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md
index 62ea05ab401bfee4e1878b7eb85ae9571e0ef2cc..612c3284a3321604c25b727c88f5516ce54e72cc 100644
--- a/DEPENDENCIES.md
+++ b/DEPENDENCIES.md
@@ -11,6 +11,7 @@ PHP Dependencies:
 - [getID3](https://github.com/JamesHeinrich/getID3) ([GNU General Public License v3](https://github.com/JamesHeinrich/getID3/blob/2.0/licenses/license.gpl-30.txt))
 - [myth-auth](https://github.com/lonnieezell/myth-auth) ([MIT license](https://github.com/lonnieezell/myth-auth/blob/develop/LICENSE.md))
 - [commonmark](https://commonmark.thephpleague.com/) ([BSD 3-Clause "New" or "Revised" License](https://github.com/thephpleague/commonmark/blob/latest/LICENSE))
+- [phpdotenv](https://github.com/vlucas/phpdotenv) ([ BSD-3-Clause License ](https://github.com/vlucas/phpdotenv/blob/master/LICENSE))
 
 Javascript dependencies:
 
diff --git a/app/Config/App.php b/app/Config/App.php
index 55952114ae9d7933c79087e95ba45aef93f36513..f05de3d87ef176bd032040f91b56e373896fa07e 100644
--- a/app/Config/App.php
+++ b/app/Config/App.php
@@ -34,7 +34,7 @@ class App extends BaseConfig
     | variable so that it is blank.
     |
     */
-    public $indexPage = 'index.php';
+    public $indexPage = '';
 
     /*
     |--------------------------------------------------------------------------
@@ -281,7 +281,7 @@ class App extends BaseConfig
     |--------------------------------------------------------------------------
     | Defines a base route for all admin pages
     */
-    public $adminGateway = 'admin';
+    public $adminGateway = 'cp-admin';
 
     /*
     |--------------------------------------------------------------------------
@@ -289,5 +289,5 @@ class App extends BaseConfig
     |--------------------------------------------------------------------------
     | Defines a base route for all authentication related pages
     */
-    public $authGateway = 'auth';
+    public $authGateway = 'cp-auth';
 }
diff --git a/app/Config/Database.php b/app/Config/Database.php
index a77c5865d3ff0e99a6464e1562c71b8b53a10a3c..408536759225ddd0da59152c6425e433fbbb2906 100644
--- a/app/Config/Database.php
+++ b/app/Config/Database.php
@@ -38,7 +38,7 @@ class Database extends \CodeIgniter\Database\Config
         'password' => '',
         'database' => '',
         'DBDriver' => 'MySQLi',
-        'DBPrefix' => '',
+        'DBPrefix' => 'cp_',
         'pConnect' => false,
         'DBDebug' => ENVIRONMENT !== 'production',
         'cacheOn' => false,
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index f65494dde758f3c5ef5c529b99fabc600e9fd26f..dc8d3ce95b5e9214237f2d5d2bb96aeba87ad005 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -31,7 +31,6 @@ $routes->setAutoRoute(false);
 
 $routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,191}');
 $routes->addPlaceholder('episodeSlug', '[a-zA-Z0-9\-]{1,191}');
-$routes->addPlaceholder('username', '[a-zA-Z0-9 ]{3,}');
 
 /**
  * --------------------------------------------------------------------
@@ -43,6 +42,17 @@ $routes->addPlaceholder('username', '[a-zA-Z0-9 ]{3,}');
 // route since we don't have to scan directories.
 $routes->get('/', 'Home::index', ['as' => 'home']);
 
+// Install Wizard route
+$routes->group('cp-install', function ($routes) {
+    $routes->get('/', 'Install', ['as' => 'install']);
+    $routes->post('generate-env', 'Install::attemptCreateEnv', [
+        'as' => 'install_generate_env',
+    ]);
+    $routes->post('create-superadmin', 'Install::attemptCreateSuperAdmin', [
+        'as' => 'install_create_superadmin',
+    ]);
+});
+
 // Public routes
 $routes->group('@(:podcastName)', function ($routes) {
     $routes->get('/', 'Podcast/$1', ['as' => 'podcast']);
@@ -68,7 +78,7 @@ $routes->group(
     ['namespace' => 'App\Controllers\Admin'],
     function ($routes) {
         $routes->get('/', 'Home', [
-            'as' => 'admin_home',
+            'as' => 'admin',
         ]);
 
         $routes->get('my-podcasts', 'Podcast::myPodcasts', [
diff --git a/app/Controllers/Install.php b/app/Controllers/Install.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd5f4f6835369a222e9dc3f5ae02a4bdad1a1e1d
--- /dev/null
+++ b/app/Controllers/Install.php
@@ -0,0 +1,270 @@
+<?php
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Controllers;
+
+use App\Models\UserModel;
+use Config\Services;
+use Dotenv\Dotenv;
+use Exception;
+
+class Install extends BaseController
+{
+    /**
+     * Every operation goes through this method to handle
+     * the install logic.
+     *
+     * If all required actions have already been performed,
+     * the install route will show a 404 page.
+     */
+    public function index()
+    {
+        try {
+            // Check if .env is created and has all required fields
+            $dotenv = Dotenv::createImmutable(ROOTPATH);
+
+            $dotenv->load();
+            $dotenv->required([
+                'app.baseURL',
+                'app.adminGateway',
+                'app.authGateway',
+                'database.default.hostname',
+                'database.default.database',
+                'database.default.username',
+                'database.default.password',
+                'database.default.DBPrefix',
+            ]);
+        } catch (\Throwable $e) {
+            // Invalid .env file
+            return $this->createEnv();
+        }
+
+        // Check if database configuration is ok
+        try {
+            $db = db_connect();
+
+            // Check if superadmin has been created, meaning migrations and seeds have passed
+            if (
+                $db->tableExists('users') &&
+                (new UserModel())->countAll() > 0
+            ) {
+                // if so, show a 404 page
+                throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
+            }
+        } catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
+            // return an error view to
+            return view('install/error', [
+                'error' => lang('Install.messages.databaseConnectError'),
+            ]);
+        }
+
+        // migrate if no user has been created
+        $this->migrate();
+
+        // Check if all seeds have succeeded
+        $this->seed();
+
+        return $this->createSuperAdmin();
+    }
+
+    /**
+     * Returns the form to generate the .env config file for the instance.
+     */
+    public function createEnv()
+    {
+        helper('form');
+
+        return view('install/env');
+    }
+
+    /**
+     * Verifies that all fields have been submitted correctly and
+     * creates the .env file after user submits the install form.
+     */
+    public function attemptCreateEnv()
+    {
+        if (
+            !$this->validate([
+                'hostname' => 'required|valid_url',
+                'admin_gateway' => 'required|differs[auth_gateway]',
+                'auth_gateway' => 'required|differs[admin_gateway]',
+                'db_hostname' => 'required',
+                'db_name' => 'required',
+                'db_username' => 'required',
+                'db_password' => 'required',
+            ])
+        ) {
+            return redirect()
+                ->back()
+                ->with('errors', $this->validator->getErrors());
+        }
+
+        // Create .env file with post data
+        try {
+            $envFile = fopen(ROOTPATH . '.env', 'w');
+            if (!$envFile) {
+                throw new Exception('File open failed.');
+            }
+
+            $envMapping = [
+                [
+                    'key' => 'app.baseURL',
+                    'value' => $this->request->getPost('hostname'),
+                ],
+                [
+                    'key' => 'app.adminGateway',
+                    'value' => $this->request->getPost('admin_gateway'),
+                ],
+                [
+                    'key' => 'app.authGateway',
+                    'value' => $this->request->getPost('auth_gateway'),
+                ],
+                [
+                    'key' => 'database.default.hostname',
+                    'value' => $this->request->getPost('db_hostname'),
+                ],
+                [
+                    'key' => 'database.default.database',
+                    'value' => $this->request->getPost('db_name'),
+                ],
+                [
+                    'key' => 'database.default.username',
+                    'value' => $this->request->getPost('db_username'),
+                ],
+                [
+                    'key' => 'database.default.password',
+                    'value' => $this->request->getPost('db_password'),
+                ],
+                [
+                    'key' => 'database.default.DBPrefix',
+                    'value' => $this->request->getPost('db_prefix'),
+                ],
+            ];
+
+            foreach ($envMapping as $envVar) {
+                if ($envVar['value']) {
+                    fwrite(
+                        $envFile,
+                        $envVar['key'] . '="' . $envVar['value'] . '"' . PHP_EOL
+                    );
+                }
+            }
+
+            return redirect()->back();
+        } catch (\Throwable $e) {
+            return redirect()
+                ->back()
+                ->with('error', $e->getMessage());
+        } finally {
+            fclose($envFile);
+        }
+    }
+
+    /**
+     * Runs all database migrations required for instance.
+     */
+    public function migrate()
+    {
+        $migrations = \Config\Services::migrations();
+
+        if (
+            !$migrations->setNamespace('Myth\Auth')->latest() or
+            !$migrations->setNamespace(APP_NAMESPACE)->latest()
+        ) {
+            return view('install/error', [
+                'error' => lang('Install.messages.migrationError'),
+            ]);
+        }
+    }
+
+    /**
+     * Runs all database seeds required for instance.
+     */
+    public function seed()
+    {
+        try {
+            $seeder = \Config\Database::seeder();
+
+            // Seed database
+            $seeder->call('AppSeeder');
+        } catch (\Throwable $e) {
+            return view('install/error', [
+                'error' => lang('Install.messages.seedError'),
+            ]);
+        }
+    }
+
+    /**
+     * Returns the form to create a the first superadmin user for the instance.
+     */
+    public function createSuperAdmin()
+    {
+        helper('form');
+
+        return view('install/superadmin');
+    }
+
+    /**
+     * Creates the first superadmin user or redirects back to form if any error.
+     *
+     * After creation, user is redirected to login page to input its credentials.
+     */
+    public function attemptCreateSuperAdmin()
+    {
+        $userModel = new UserModel();
+
+        // Validate here first, since some things,
+        // like the password, can only be validated properly here.
+        $rules = array_merge(
+            $userModel->getValidationRules(['only' => ['username']]),
+            [
+                'email' => 'required|valid_email|is_unique[users.email]',
+                'password' => 'required|strong_password',
+            ]
+        );
+
+        if (!$this->validate($rules)) {
+            return redirect()
+                ->back()
+                ->withInput()
+                ->with('errors', $this->validator->getErrors());
+        }
+
+        // Save the user
+        $user = new \App\Entities\User($this->request->getPost());
+
+        // Activate user
+        $user->activate();
+
+        $db = \Config\Database::connect();
+
+        $db->transStart();
+        if (!($userId = $userModel->insert($user, true))) {
+            $db->transComplete();
+
+            return redirect()
+                ->back()
+                ->withInput()
+                ->with('errors', $userModel->errors());
+        }
+
+        // add newly created user to superadmin group
+        $authorization = Services::authorization();
+        $authorization->addUserToGroup($userId, 'superadmin');
+
+        $db->transComplete();
+
+        // Success!
+        // set redirect url to admin page after being redirected to login page
+        $_SESSION['redirect_url'] = route_to('admin');
+
+        return redirect()
+            ->route('login')
+            ->with('message', lang('Install.messages.createSuperAdminSuccess'));
+    }
+}
diff --git a/app/Controllers/Migrate.php b/app/Controllers/Migrate.php
deleted file mode 100644
index 6cf2b699231103a949f89c0bdfc546ff7e0b3e5e..0000000000000000000000000000000000000000
--- a/app/Controllers/Migrate.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-namespace App\Controllers;
-
-use CodeIgniter\Controller;
-
-class Migrate extends Controller
-{
-    public function index()
-    {
-        $migrate = \Config\Services::migrations();
-
-        try {
-            $migrate->latest();
-        } catch (\Exception $e) {
-            // Do something with the error here...
-        }
-    }
-}
diff --git a/app/Database/Seeds/AppSeeder.php b/app/Database/Seeds/AppSeeder.php
new file mode 100644
index 0000000000000000000000000000000000000000..6dac6af4d6aa47878630dd46642420a852546d11
--- /dev/null
+++ b/app/Database/Seeds/AppSeeder.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Class AppSeeder
+ * Calls all required seeders for castopod to work properly
+ *
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Database\Seeds;
+
+use CodeIgniter\Database\Seeder;
+
+class AppSeeder extends Seeder
+{
+    public function run()
+    {
+        $this->call('AuthSeeder');
+        $this->call('CategorySeeder');
+        $this->call('LanguageSeeder');
+        $this->call('PlatformSeeder');
+    }
+}
diff --git a/app/Language/en/AdminNavigation.php b/app/Language/en/AdminNavigation.php
index 714502a495e742292b844bafb7c292fcfa062d6d..255e1b5ed09c999a166a3e835b9b6e636e65535b 100644
--- a/app/Language/en/AdminNavigation.php
+++ b/app/Language/en/AdminNavigation.php
@@ -10,7 +10,7 @@ return [
     'dashboard' => 'Dashboard',
     'podcasts' => 'Podcasts',
     'users' => 'Users',
-    'admin_home' => 'Home',
+    'admin' => 'Home',
     'my_podcasts' => 'My podcasts',
     'podcast_list' => 'All podcasts',
     'podcast_create' => 'New podcast',
diff --git a/app/Language/en/Install.php b/app/Language/en/Install.php
new file mode 100644
index 0000000000000000000000000000000000000000..ede3aa9391fce57f453c911449af1915cf0e6b82
--- /dev/null
+++ b/app/Language/en/Install.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'form' => [
+        'castopod_config' => 'Castopod configuration',
+        'hostname' => 'Hostname',
+        'admin_gateway' => 'Admin gateway',
+        'auth_gateway' => 'Auth gateway',
+        'db_config' => 'Database configuration',
+        'db_hostname' => 'Database hostname',
+        'db_name' => 'Database name',
+        'db_username' => 'Database username',
+        'db_password' => 'Database password',
+        'db_prefix' => 'Database prefix',
+        'submit_install' => 'Install!',
+        'create_superadmin' => 'Create your superadmin account',
+        'email' => 'Email',
+        'username' => 'Username',
+        'password' => 'Password',
+        'submit_create_superadmin' => 'Create superadmin!',
+    ],
+    'messages' => [
+        'migrateSuccess' =>
+            'Database has been created successfully, and all required data have been stored!',
+        'createSuperAdminSuccess' =>
+            'Your superadmin account has been created successfully. Let\'s login to the admin area!',
+        'databaseConnectError' =>
+            'Unable to connect to the database. Make sure the values in .env are correct. If not, edit them and refresh the page or delete the .env file to restart install.',
+        'migrationError' =>
+            'There was an issue during migration. Make sure the values in .env are correct. If not, edit them and refresh the page or delete the .env file to restart install.',
+        'seedError' =>
+            'There was an issue when seeding the database. Make sure the values in .env are correct. If not, edit them and refresh the page or delete the .env file to restart install.',
+        'error' =>
+            '<strong>An error occurred during install</strong><br/> {message}',
+    ],
+];
diff --git a/app/Views/admin/_header.php b/app/Views/admin/_header.php
index b97236e3cf7829abf2332ae91be094cb7ce8d20a..6756660b62498dcfc41e97397dca3cd631c2ae4f 100644
--- a/app/Views/admin/_header.php
+++ b/app/Views/admin/_header.php
@@ -1,7 +1,7 @@
 <header class="<?= $class ?>">
     <div class="w-64">
         <a href="<?= route_to(
-            'admin_home'
+            'admin'
         ) ?>" class="inline-flex items-center text-xl">
             <?= svg('logo-castopod', 'text-3xl mr-2') ?>
             Admin
diff --git a/app/Views/admin/_sidenav.php b/app/Views/admin/_sidenav.php
index fa349177e1159796f9062149e296aa81a9d76a67..dad0054913c6f52efe7457640ef60a8738bc647b 100644
--- a/app/Views/admin/_sidenav.php
+++ b/app/Views/admin/_sidenav.php
@@ -1,6 +1,6 @@
 <?php
 $navigation = [
-    'dashboard' => ['icon' => 'dashboard', 'items' => ['admin_home']],
+    'dashboard' => ['icon' => 'dashboard', 'items' => ['admin']],
     'podcasts' => [
         'icon' => 'mic',
         'items' => ['my_podcasts', 'podcast_list', 'podcast_create'],
diff --git a/app/Views/install/_layout.php b/app/Views/install/_layout.php
new file mode 100644
index 0000000000000000000000000000000000000000..81f634ff01812a52788976990da0aa8220e7fa4b
--- /dev/null
+++ b/app/Views/install/_layout.php
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8"/>
+    <title>Castopod</title>
+    <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="stylesheet" href="/assets/index.css"/>
+</head>
+
+<body class="flex flex-col min-h-screen mx-auto">
+    <header class="border-b">
+        <div class="container flex items-center justify-between px-2 py-4 mx-auto">
+            Castopod installer
+        </div>
+    </header>
+    <main class="container flex-1 px-4 py-10 mx-auto">
+        <?= view('_message_block') ?>
+        <?= $this->renderSection('content') ?>
+    </main>
+    <footer class="container px-2 py-4 mx-auto text-sm text-right border-t">
+        Powered by <a class="underline hover:no-underline" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod</a>, a <a class="underline hover:no-underline" href="https://podlibre.org/" target="_blank" rel="noreferrer noopener">Podlibre</a> initiative.
+    </footer>
+</body>
diff --git a/app/Views/install/env.php b/app/Views/install/env.php
new file mode 100644
index 0000000000000000000000000000000000000000..d41eff3fb5a07978828ef59ad52e529fd634c20c
--- /dev/null
+++ b/app/Views/install/env.php
@@ -0,0 +1,89 @@
+<?= $this->extend('install/_layout') ?>
+
+<?= $this->section('content') ?>
+
+<?= form_open(route_to('install_generate_env'), [
+    'class' => 'flex flex-col max-w-sm mx-auto',
+]) ?>
+
+<?= form_fieldset('', ['class' => 'flex flex-col mb-6']) ?>
+    <legend class="mb-4 text-xl"><?= lang(
+        'Install.form.castopod_config'
+    ) ?></legend>
+    <?= form_label(lang('Install.form.hostname'), 'hostname') ?>
+    <?= form_input([
+        'id' => 'hostname',
+        'name' => 'hostname',
+        'class' => 'form-input mb-4',
+        'value' => config('App')->baseURL,
+    ]) ?>
+
+    <?= form_label(lang('Install.form.admin_gateway'), 'admin_gateway') ?>
+    <?= form_input([
+        'id' => 'admin_gateway',
+        'name' => 'admin_gateway',
+        'class' => 'form-input mb-4',
+        'value' => config('App')->adminGateway,
+    ]) ?>
+
+    <?= form_label(lang('Install.form.auth_gateway'), 'auth_gateway') ?>
+    <?= form_input([
+        'id' => 'auth_gateway',
+        'name' => 'auth_gateway',
+        'class' => 'form-input',
+        'value' => config('App')->authGateway,
+    ]) ?>
+<?= form_fieldset_close() ?>
+
+<?= form_fieldset('', ['class' => 'flex flex-col mb-6']) ?>
+    <legend class="mb-4 text-xl"><?= lang('Install.form.db_config') ?></legend>
+    <?= form_label(lang('Install.form.db_hostname'), 'db_hostname') ?>
+    <?= form_input([
+        'id' => 'db_hostname',
+        'name' => 'db_hostname',
+        'class' => 'form-input mb-4',
+        'value' => config('Database')->default['hostname'],
+    ]) ?>
+
+    <?= form_label(lang('Install.form.db_name'), 'db_name') ?>
+    <?= form_input([
+        'id' => 'db_name',
+        'name' => 'db_name',
+        'class' => 'form-input mb-4',
+        'value' => config('Database')->default['database'],
+    ]) ?>
+
+    <?= form_label(lang('Install.form.db_username'), 'db_username') ?>
+    <?= form_input([
+        'id' => 'db_username',
+        'name' => 'db_username',
+        'class' => 'form-input mb-4',
+        'value' => config('Database')->default['username'],
+    ]) ?>
+
+    <?= form_label(lang('Install.form.db_password'), 'db_password') ?>
+    <?= form_input([
+        'id' => 'db_password',
+        'name' => 'db_password',
+        'class' => 'form-input mb-4',
+        'value' => config('Database')->default['password'],
+    ]) ?>
+
+    <?= form_label(lang('Install.form.db_prefix'), 'db_prefix') ?>
+    <?= form_input([
+        'id' => 'db_prefix',
+        'name' => 'db_prefix',
+        'class' => 'form-input',
+        'value' => config('Database')->default['DBPrefix'],
+    ]) ?>
+<?= form_fieldset_close() ?>
+
+<?= form_button([
+    'content' => lang('Install.form.submit_install'),
+    'type' => 'submit',
+    'class' => 'self-end px-4 py-2 bg-gray-200',
+]) ?>
+
+<?= form_close() ?>
+
+<?= $this->endSection() ?>
diff --git a/app/Views/install/error.php b/app/Views/install/error.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4f8bf0ac0e0dbe4e8f4427567ac8acf9094cf86
--- /dev/null
+++ b/app/Views/install/error.php
@@ -0,0 +1,9 @@
+<?= $this->extend('install/_layout') ?>
+
+<?= $this->section('content') ?>
+
+<div class="px-4 py-2 mb-4 font-semibold text-red-900 bg-red-200 border border-red-700">
+    <?= lang('Install.messages.error', ['message' => $error]) ?>
+</div>
+
+<?= $this->endSection() ?>
diff --git a/app/Views/install/superadmin.php b/app/Views/install/superadmin.php
new file mode 100644
index 0000000000000000000000000000000000000000..37858097ae05a93c3f8b14d56735da72f254cc7f
--- /dev/null
+++ b/app/Views/install/superadmin.php
@@ -0,0 +1,45 @@
+<?= $this->extend('install/_layout') ?>
+
+<?= $this->section('content') ?>
+
+<?= form_open(route_to('install_create_superadmin'), [
+    'class' => 'flex flex-col max-w-sm mx-auto',
+]) ?>
+
+<?= form_fieldset('', ['class' => 'flex flex-col mb-6']) ?>
+    <legend class="mb-4 text-xl"><?= lang(
+        'Install.form.create_superadmin'
+    ) ?></legend>
+    <?= form_label(lang('Install.form.email'), 'email') ?>
+    <?= form_input([
+        'id' => 'email',
+        'name' => 'email',
+        'class' => 'form-input mb-4',
+        'type' => 'email',
+    ]) ?>
+    
+    <?= form_label(lang('Install.form.username'), 'username') ?>
+    <?= form_input([
+        'id' => 'username',
+        'name' => 'username',
+        'class' => 'form-input mb-4',
+    ]) ?>
+
+    <?= form_label(lang('Install.form.password'), 'password') ?>
+    <?= form_input([
+        'id' => 'password',
+        'name' => 'password',
+        'class' => 'form-input',
+        'type' => 'password',
+    ]) ?>
+<?= form_fieldset_close() ?>
+
+<?= form_button([
+    'content' => lang('Install.form.submit_create_superadmin'),
+    'type' => 'submit',
+    'class' => 'self-end px-4 py-2 bg-gray-200',
+]) ?>
+
+<?= form_close() ?>
+
+<?= $this->endSection() ?>
diff --git a/composer.json b/composer.json
index c5f29a4aef91c51216d9647c21221fa370200b10..44be1c8c6563b40442ea34f620644b0b441131ef 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,8 @@
     "geoip2/geoip2": "~2.0",
     "myth/auth": "dev-develop",
     "codeigniter4/codeigniter4": "dev-develop",
-    "league/commonmark": "^1.5"
+    "league/commonmark": "^1.5",
+    "vlucas/phpdotenv": "^5.1"
   },
   "require-dev": {
     "mikey179/vfsstream": "1.6.*",
diff --git a/composer.lock b/composer.lock
index 1d5b5b7c8513e1940068020de852ece2a0564880..bdeba108ecebe0921036973e38a145bfae962759 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "1fe52c47fa9834960fdb1cf37f2f2776",
+    "content-hash": "a6be291e1c7f73b73182cd7b49234688",
     "packages": [
         {
             "name": "codeigniter4/codeigniter4",
@@ -186,6 +186,68 @@
             ],
             "time": "2019-12-12T18:48:39+00:00"
         },
+        {
+            "name": "graham-campbell/result-type",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/GrahamCampbell/Result-Type.git",
+                "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb",
+                "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0|^8.0",
+                "phpoption/phpoption": "^1.7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GrahamCampbell\\ResultType\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com"
+                }
+            ],
+            "description": "An Implementation Of The Result Type",
+            "keywords": [
+                "Graham Campbell",
+                "GrahamCampbell",
+                "Result Type",
+                "Result-Type",
+                "result"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-04-13T13:17:36+00:00"
+        },
         {
             "name": "james-heinrich/getid3",
             "version": "v2.0.0-beta3",
@@ -705,6 +767,71 @@
             ],
             "time": "2020-07-16T14:00:14+00:00"
         },
+        {
+            "name": "phpoption/phpoption",
+            "version": "1.7.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/schmittjoh/php-option.git",
+                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525",
+                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpOption\\": "src/PhpOption/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Johannes M. Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com"
+                }
+            ],
+            "description": "Option Type for PHP",
+            "keywords": [
+                "language",
+                "option",
+                "php",
+                "type"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-20T17:29:33+00:00"
+        },
         {
             "name": "psr/cache",
             "version": "1.0.1",
@@ -798,6 +925,315 @@
             ],
             "time": "2020-03-23T09:12:05+00:00"
         },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.18.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.18-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-14T12:35:20+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.18.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a",
+                "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.18-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-14T12:35:20+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.18.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981",
+                "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.18-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ],
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-14T12:35:20+00:00"
+        },
+        {
+            "name": "vlucas/phpdotenv",
+            "version": "v5.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vlucas/phpdotenv.git",
+                "reference": "448c76d7a9e30c341ff5bc367a923af74ae18467"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/448c76d7a9e30c341ff5bc367a923af74ae18467",
+                "reference": "448c76d7a9e30c341ff5bc367a923af74ae18467",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "graham-campbell/result-type": "^1.0.1",
+                "php": "^7.1.3 || ^8.0",
+                "phpoption/phpoption": "^1.7.4",
+                "symfony/polyfill-ctype": "^1.17",
+                "symfony/polyfill-mbstring": "^1.17",
+                "symfony/polyfill-php80": "^1.17"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "ext-filter": "*",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.2 || ^9.0"
+            },
+            "suggest": {
+                "ext-filter": "Required to use the boolean validator."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Dotenv\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com",
+                    "homepage": "https://gjcampbell.co.uk/"
+                },
+                {
+                    "name": "Vance Lucas",
+                    "email": "vance@vancelucas.com",
+                    "homepage": "https://vancelucas.com/"
+                }
+            ],
+            "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+            "keywords": [
+                "dotenv",
+                "env",
+                "environment"
+            ],
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-07-14T19:26:25+00:00"
+        },
         {
             "name": "whichbrowser/parser",
             "version": "v2.0.42",
@@ -2351,82 +2787,6 @@
             ],
             "time": "2020-04-17T01:09:41+00:00"
         },
-        {
-            "name": "symfony/polyfill-ctype",
-            "version": "v1.18.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
-                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-ctype": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.18-dev"
-                },
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Ctype\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Gert de Pagter",
-                    "email": "BackEndTea@gmail.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for ctype functions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "ctype",
-                "polyfill",
-                "portable"
-            ],
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2020-07-14T12:35:20+00:00"
-        },
         {
             "name": "theseer/tokenizer",
             "version": "1.2.0",
diff --git a/public/favicon.ico b/public/favicon.ico
index aa74302f6ff59e0fb3327fc9511f4116636bb5cb..3a7011d31145b36525ab60c8ed7dc0dbf07d7303 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ