diff --git a/.gitignore b/.gitignore
index 47f4c37308690361ce00fb9c3edfad97c4c03ab7..4ed935bc0b98aaeebada38686f79f69be52da56d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,9 +137,11 @@ node_modules
 
 # public folder
 public/*
+public/media/site
 !public/media
 !public/.htaccess
 !public/favicon.ico
+!public/icon*
 !public/index.php
 !public/robots.txt
 
diff --git a/app/Config/App.php b/app/Config/App.php
index df445db0ed909e63448d7fe30e379ef8b4f4083d..4d2227c0873e28f145ab412ce3269f4b510b919c 100644
--- a/app/Config/App.php
+++ b/app/Config/App.php
@@ -427,4 +427,24 @@ class App extends BaseConfig
      * Defines the root folder for media files storage
      */
     public string $mediaRoot = 'media';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Instance / Site Config
+     * --------------------------------------------------------------------------
+     */
+    public string $siteName = 'Castopod';
+
+    public string $siteDescription = 'Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.';
+
+    /**
+     * @var array<int|string, string>
+     */
+    public array $siteIcon = [
+        'ico' => '/favicon.ico',
+        '64' => '/icon-64.png',
+        '180' => '/icon-180.png',
+        '192' => '/icon-192.png',
+        '512' => '/icon-512.png',
+    ];
 }
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 45eff6b951398187e732c9314a89febe178a1df7..7d2ca19f731c82e43055b9850624a0a6a5ff9344 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -48,9 +48,13 @@ $routes->addPlaceholder(
  * --------------------------------------------------------------------
  */
 
+$routes->get('manifest.webmanifest', 'WebmanifestController', [
+    'as' => 'webmanifest',
+]);
+
 // We get a performance increase by specifying the default
 // route since we don't have to scan directories.
-$routes->get('/', 'HomeController::index', [
+$routes->get('/', 'HomeController', [
     'as' => 'home',
 ]);
 
diff --git a/app/Controllers/WebmanifestController.php b/app/Controllers/WebmanifestController.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd320e440e5cc680aa1929d6c7bb6655b1c6c1f5
--- /dev/null
+++ b/app/Controllers/WebmanifestController.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @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;
+use CodeIgniter\HTTP\ResponseInterface;
+
+class WebmanifestController extends Controller
+{
+    public function index(): ResponseInterface
+    {
+        $webmanifest = [
+            'name' => service('settings')
+                ->get('App.siteName'),
+            'description' => service('settings')
+                ->get('App.siteDescription'),
+            'display' => 'minimal-ui',
+            'theme_color' => '#009486',
+            'icons' => [
+                [
+                    'src' => service('settings')
+                        ->get('App.siteIcon')['192'],
+                    'type' => 'image/png',
+                    'sizes' => '192x192',
+                ],
+                [
+                    'src' => service('settings')
+                        ->get('App.siteIcon')['512'],
+                    'type' => 'image/png',
+                    'sizes' => '512x512',
+                ],
+            ],
+        ];
+
+        return $this->response->setJSON($webmanifest);
+    }
+}
diff --git a/app/Database/Seeds/AuthSeeder.php b/app/Database/Seeds/AuthSeeder.php
index 2fb6fb6a28d1c74729a09a97c6b0cab2d7c4e5b1..eb9af6a760a57f971135b813551fa569e6737a3b 100644
--- a/app/Database/Seeds/AuthSeeder.php
+++ b/app/Database/Seeds/AuthSeeder.php
@@ -40,6 +40,18 @@ class AuthSeeder extends Seeder
      * @var array<string, array<string, string|array>[]>
      */
     protected array $permissions = [
+        'settings' => [
+            [
+                'name' => 'view',
+                'description' => 'View settings options',
+                'has_permission' => ['superadmin'],
+            ],
+            [
+                'name' => 'manage',
+                'description' => 'Update general settings',
+                'has_permission' => ['superadmin'],
+            ],
+        ],
         'users' => [
             [
                 'name' => 'create',
diff --git a/app/Helpers/media_helper.php b/app/Helpers/media_helper.php
index 312af42a3b540a37dc88f515b736ff4cc86fb349..b9a1c65bf72abef3e410c4d517bd802d3c7c6582 100644
--- a/app/Helpers/media_helper.php
+++ b/app/Helpers/media_helper.php
@@ -29,6 +29,9 @@ if (! function_exists('save_media')) {
 
         if (! file_exists($mediaRoot)) {
             mkdir($mediaRoot, 0777, true);
+        }
+
+        if (! file_exists($mediaRoot . '/index.html')) {
             touch($mediaRoot . '/index.html');
         }
 
diff --git a/composer.json b/composer.json
index 3ca24a4fc59bcbfa068700c069238640881303c2..b7dffcaf402d6e2ca6017f1da7ef98e4d48d66fe 100644
--- a/composer.json
+++ b/composer.json
@@ -12,15 +12,17 @@
     "geoip2/geoip2": "^v2.11.0",
     "myth/auth": "dev-develop",
     "codeigniter4/codeigniter4": "dev-develop",
-    "league/commonmark": "^1.6.6",
+    "league/commonmark": "^v1.6.6",
     "vlucas/phpdotenv": "^v5.3.0",
-    "league/html-to-markdown": "^5.0.0",
+    "league/html-to-markdown": "^v5.0.1",
     "opawg/user-agents-php": "^v1.0",
     "podlibre/ipcat": "^v1.0",
     "podlibre/podcast-namespace": "^v1.0.6",
     "phpseclib/phpseclib": "~2.0.30",
     "michalsn/codeigniter4-uuid": "dev-develop",
-    "essence/essence": "^3.5.4"
+    "essence/essence": "^3.5.4",
+    "codeigniter4/settings": "dev-develop",
+    "chrisjean/php-ico": "^1.0"
   },
   "require-dev": {
     "mikey179/vfsstream": "^v1.6.8",
diff --git a/composer.lock b/composer.lock
index 03baaec32bcf025caf8d4185c8db480c81e74958..82b1287a717d7bc55e249105cad9a44e797c9881 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": "af4a438816f7adbbd6950d93ed333e9f",
+  "content-hash": "f35a050323bdc632cd550f9d13f0679c",
   "packages": [
     {
       "name": "brick/math",
@@ -60,6 +60,46 @@
       ],
       "time": "2021-01-20T22:51:39+00:00"
     },
+    {
+      "name": "chrisjean/php-ico",
+      "version": "1.0.4",
+      "source": {
+        "type": "git",
+        "url": "https://github.com/chrisbliss18/php-ico.git",
+        "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6"
+      },
+      "dist": {
+        "type": "zip",
+        "url": "https://api.github.com/repos/chrisbliss18/php-ico/zipball/ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
+        "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
+        "shasum": ""
+      },
+      "require": {
+        "ext-gd": "*",
+        "php": ">=5.2.4"
+      },
+      "type": "library",
+      "autoload": {
+        "classmap": ["class-php-ico.php"]
+      },
+      "notification-url": "https://packagist.org/downloads/",
+      "license": ["GPL-2.0+"],
+      "authors": [
+        {
+          "name": "Chris Jean",
+          "homepage": "https://chrisjean.com",
+          "role": "Developer"
+        }
+      ],
+      "description": "An easy-to-use library to generate valid ICO files.",
+      "homepage": "https://github.com/chrisbliss18/php-ico",
+      "keywords": ["favicon", "ico"],
+      "support": {
+        "issues": "https://github.com/chrisbliss18/php-ico/issues",
+        "source": "https://github.com/chrisbliss18/php-ico"
+      },
+      "time": "2016-09-27T22:00:56+00:00"
+    },
     {
       "name": "codeigniter4/codeigniter4",
       "version": "dev-develop",
@@ -137,6 +177,59 @@
       },
       "time": "2021-06-10T06:40:05+00:00"
     },
+    {
+      "name": "codeigniter4/settings",
+      "version": "dev-develop",
+      "source": {
+        "type": "git",
+        "url": "https://github.com/codeigniter4/settings.git",
+        "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577"
+      },
+      "dist": {
+        "type": "zip",
+        "url": "https://api.github.com/repos/codeigniter4/settings/zipball/5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
+        "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
+        "shasum": ""
+      },
+      "require": {
+        "php": "^7.3 || ^8.0"
+      },
+      "require-dev": {
+        "codeigniter4/codeigniter4": "dev-develop",
+        "fakerphp/faker": "^1.9",
+        "mockery/mockery": "^1.0",
+        "nexusphp/tachycardia": "^1.0",
+        "php-coveralls/php-coveralls": "^2.4",
+        "phpstan/phpstan": "^0.12",
+        "phpunit/phpunit": "^9.0",
+        "squizlabs/php_codesniffer": "^3.3"
+      },
+      "default-branch": true,
+      "type": "library",
+      "autoload": {
+        "psr-4": {
+          "Sparks\\Settings\\": "src"
+        },
+        "exclude-from-classmap": ["**/Database/Migrations/**"]
+      },
+      "notification-url": "https://packagist.org/downloads/",
+      "license": ["MIT"],
+      "authors": [
+        {
+          "name": "Lonnie Ezell",
+          "email": "lonnieje@gmail.com",
+          "role": "Developer"
+        }
+      ],
+      "description": "Settings library for CodeIgniter 4",
+      "homepage": "https://github.com/codeigniter4/settings",
+      "keywords": ["Settings", "codeigniter", "codeigniter4"],
+      "support": {
+        "issues": "https://github.com/codeigniter4/settings/issues",
+        "source": "https://github.com/codeigniter4/settings/tree/develop"
+      },
+      "time": "2021-08-16T05:07:59+00:00"
+    },
     {
       "name": "composer/ca-bundle",
       "version": "1.2.10",
@@ -494,16 +587,16 @@
     },
     {
       "name": "james-heinrich/getid3",
-      "version": "2.0.x-dev",
+      "version": "v2.0.0-beta4",
       "source": {
         "type": "git",
         "url": "https://github.com/JamesHeinrich/getID3.git",
-        "reference": "ee238d552571c6029898b087d5fc95df826418d6"
+        "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/ee238d552571c6029898b087d5fc95df826418d6",
-        "reference": "ee238d552571c6029898b087d5fc95df826418d6",
+        "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
+        "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
         "shasum": ""
       },
       "require": {
@@ -562,9 +655,9 @@
       "keywords": ["audio", "codecs", "id3", "metadata", "tags", "video"],
       "support": {
         "issues": "https://github.com/JamesHeinrich/getID3/issues",
-        "source": "https://github.com/JamesHeinrich/getID3/tree/2.0"
+        "source": "https://github.com/JamesHeinrich/getID3/tree/v2.0.0-beta4"
       },
-      "time": "2021-12-15T17:29:14+00:00"
+      "time": "2021-10-06T16:23:45+00:00"
     },
     {
       "name": "kint-php/kint",
@@ -745,16 +838,16 @@
     },
     {
       "name": "league/commonmark",
-      "version": "1.6.2",
+      "version": "1.6.6",
       "source": {
         "type": "git",
         "url": "https://github.com/thephpleague/commonmark.git",
-        "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb"
+        "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7d70d2f19c84bcc16275ea47edabee24747352eb",
-        "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb",
+        "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4228d11e30d7493c6836d20872f9582d8ba6dcf",
+        "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf",
         "shasum": ""
       },
       "require": {
@@ -772,7 +865,7 @@
         "github/gfm": "0.29.0",
         "michelf/php-markdown": "~1.4",
         "mikehaertl/php-shellcommand": "^1.4",
-        "phpstan/phpstan": "^0.12",
+        "phpstan/phpstan": "^0.12.90",
         "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
         "scrutinizer/ocular": "^1.5",
         "symfony/finder": "^4.2"
@@ -838,37 +931,40 @@
           "type": "tidelift"
         }
       ],
-      "time": "2021-05-12T11:39:41+00:00"
+      "time": "2021-07-17T17:13:23+00:00"
     },
     {
       "name": "league/html-to-markdown",
-      "version": "4.10.0",
+      "version": "5.0.1",
       "source": {
         "type": "git",
         "url": "https://github.com/thephpleague/html-to-markdown.git",
-        "reference": "0868ae7a552e809e5cd8f93ba022071640408e88"
+        "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0868ae7a552e809e5cd8f93ba022071640408e88",
-        "reference": "0868ae7a552e809e5cd8f93ba022071640408e88",
+        "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e5600a2c5ce7b7571b16732c7086940f56f7abec",
+        "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec",
         "shasum": ""
       },
       "require": {
         "ext-dom": "*",
         "ext-xml": "*",
-        "php": ">=5.3.3"
+        "php": "^7.2.5 || ^8.0"
       },
       "require-dev": {
-        "mikehaertl/php-shellcommand": "~1.1.0",
-        "phpunit/phpunit": "^4.8|^5.7",
-        "scrutinizer/ocular": "~1.1"
+        "mikehaertl/php-shellcommand": "^1.1.0",
+        "phpstan/phpstan": "^0.12.82",
+        "phpunit/phpunit": "^8.5 || ^9.2",
+        "scrutinizer/ocular": "^1.6",
+        "unleashedtech/php-coding-standard": "^2.7",
+        "vimeo/psalm": "^4.6"
       },
       "bin": ["bin/html-to-markdown"],
       "type": "library",
       "extra": {
         "branch-alias": {
-          "dev-master": "4.10-dev"
+          "dev-master": "5.1-dev"
         }
       },
       "autoload": {
@@ -897,7 +993,7 @@
       "keywords": ["html", "markdown"],
       "support": {
         "issues": "https://github.com/thephpleague/html-to-markdown/issues",
-        "source": "https://github.com/thephpleague/html-to-markdown/tree/4.10.0"
+        "source": "https://github.com/thephpleague/html-to-markdown/tree/5.0.1"
       },
       "funding": [
         {
@@ -913,11 +1009,11 @@
           "type": "github"
         },
         {
-          "url": "https://www.patreon.com/colinodell",
-          "type": "patreon"
+          "url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
+          "type": "tidelift"
         }
       ],
-      "time": "2020-07-01T00:34:03+00:00"
+      "time": "2021-09-17T20:00:27+00:00"
     },
     {
       "name": "maxmind-db/reader",
@@ -7457,7 +7553,8 @@
     "james-heinrich/getid3": 20,
     "myth/auth": 20,
     "codeigniter4/codeigniter4": 20,
-    "michalsn/codeigniter4-uuid": 20
+    "michalsn/codeigniter4-uuid": 20,
+    "codeigniter4/settings": 20
   },
   "prefer-stable": true,
   "prefer-lowest": false,
@@ -7465,5 +7562,5 @@
     "php": "^8.0"
   },
   "platform-dev": [],
-  "plugin-api-version": "2.0.0"
+  "plugin-api-version": "2.1.0"
 }
diff --git a/ecs.php b/ecs.php
index 939cae297db701a5878e7295d99cc1ea588fd54e..a7d4071516c268055fea7b3cdca46e8ed3d29e36 100644
--- a/ecs.php
+++ b/ecs.php
@@ -17,7 +17,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
         __DIR__ . '/themes',
         __DIR__ . '/tests',
         __DIR__ . '/public',
-        __DIR__ . '/public',
     ]);
 
     $parameters->set(Option::SKIP, [
diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php
index d259ce905c98cdbde8766717a302d56dcfcbfd16..edda5e81520efad7a2a998e9b9eb2bb2ac6663fe 100644
--- a/modules/Admin/Config/Routes.php
+++ b/modules/Admin/Config/Routes.php
@@ -18,6 +18,21 @@ $routes->group(
             'as' => 'admin',
         ]);
 
+        $routes->group('settings', function ($routes): void {
+            $routes->get('/', 'SettingsController', [
+                'as' => 'settings-general',
+                'filter' => 'permission:settings-manage',
+            ]);
+            $routes->post('instance', 'SettingsController::attemptInstanceEdit', [
+                'as' => 'settings-instance',
+                'filter' => 'permission:settings-manage',
+            ]);
+            $routes->get('instance-delete-icon', 'SettingsController::deleteIcon', [
+                'as' => 'settings-instance-delete-icon',
+                'filter' => 'permission:settings-manage',
+            ]);
+        });
+
         $routes->group('persons', function ($routes): void {
             $routes->get('/', 'PersonController', [
                 'as' => 'person-list',
diff --git a/modules/Admin/Controllers/SettingsController.php b/modules/Admin/Controllers/SettingsController.php
new file mode 100644
index 0000000000000000000000000000000000000000..1308df71f5e5531cf0c097b4e9b257ce86d4eb49
--- /dev/null
+++ b/modules/Admin/Controllers/SettingsController.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace Modules\Admin\Controllers;
+
+use CodeIgniter\HTTP\RedirectResponse;
+use PHP_ICO;
+
+class SettingsController extends BaseController
+{
+    public function index(): string
+    {
+        helper('form');
+        return view('settings/general');
+    }
+
+    public function attemptInstanceEdit(): RedirectResponse
+    {
+        $rules = [
+            'site_icon' =>
+                'is_image[site_icon]|ext_in[site_icon,png,jpeg]|is_image_squared[site_icon]|min_dims[image,512,512]|permit_empty',
+        ];
+
+        if (! $this->validate($rules)) {
+            return redirect()
+                ->back()
+                ->withInput()
+                ->with('errors', $this->validator->getErrors());
+        }
+
+        $siteName = $this->request->getPost('site_name');
+        if ($siteName !== service('settings')->get('App.siteName')) {
+            service('settings')->set('App.siteName', $siteName);
+        }
+
+        $siteDescription = $this->request->getPost('site_description');
+        if ($siteDescription !== service('settings')->get('App.siteDescription')) {
+            service('settings')->set('App.siteDescription', $siteDescription);
+        }
+
+        $siteIconFile = $this->request->getFile('site_icon');
+        if ($siteIconFile !== null && $siteIconFile->isValid()) {
+            helper(['filesystem', 'media']);
+
+            // delete site folder in media before repopulating it
+            delete_files(ROOTPATH . 'public/media/site/');
+
+            // save original in disk
+            $originalFilename = save_media($siteIconFile, 'site', 'icon');
+
+            // convert jpeg image to png if not
+            if ($siteIconFile->getClientMimeType() !== 'image/png') {
+                service('image')->withFile(ROOTPATH . 'public/media/' . $originalFilename)
+                    ->convert(IMAGETYPE_JPEG)
+                    ->save(ROOTPATH . 'public/media/site/icon.png');
+            }
+
+            // generate random hash to use as a suffix to renew browser cache
+            $randomHash = substr(bin2hex(random_bytes(18)), 0, 8);
+
+            // generate ico
+            $ico_lib = new PHP_ICO();
+            $ico_lib->add_image(ROOTPATH . 'public/media/site/icon.png', [[32, 32], [64, 64]]);
+            $ico_lib->save_ico(ROOTPATH . "public/media/site/favicon.{$randomHash}.ico");
+
+            // resize original to needed sizes
+            foreach ([64, 180, 192, 512] as $size) {
+                service('image')
+                    ->withFile(ROOTPATH . 'public/media/site/icon.png')
+                    ->resize($size, $size)
+                    ->save(ROOTPATH . "public/media/site/icon-{$size}.{$randomHash}.png");
+            }
+
+            service('settings')
+                ->set('App.siteIcon', [
+                    'ico' => "/media/site/favicon.{$randomHash}.ico",
+                    '64' => "/media/site/icon-64.{$randomHash}.png",
+                    '180' => "/media/site/icon-180.{$randomHash}.png",
+                    '192' => "/media/site/icon-192.{$randomHash}.png",
+                    '512' => "/media/site/icon-512.{$randomHash}.png",
+                ]);
+        }
+
+        return redirect()->back();
+    }
+
+    public function deleteIcon(): RedirectResponse
+    {
+        helper('filesystem');
+        // delete site folder in media
+        delete_files(ROOTPATH . 'public/media/site/');
+
+        service('settings')
+            ->forget('App.siteIcon');
+
+        return redirect()->back();
+    }
+}
diff --git a/modules/Admin/Language/en/AdminNavigation.php b/modules/Admin/Language/en/AdminNavigation.php
index 68cbefb3ebcfd0a033bb214d5ba740ed8809206a..c2e8e4b696233f1ff313c1c35a0fb12fd1a604fc 100644
--- a/modules/Admin/Language/en/AdminNavigation.php
+++ b/modules/Admin/Language/en/AdminNavigation.php
@@ -29,6 +29,8 @@ return [
     'pages' => 'Pages',
     'page-list' => 'All pages',
     'page-create' => 'New Page',
+    'settings' => 'Settings',
+    'settings-general' => 'General',
     'account' => [
         'my-account' => 'My account',
         'change-password' => 'Change password',
diff --git a/modules/Admin/Language/en/Breadcrumb.php b/modules/Admin/Language/en/Breadcrumb.php
index 9a1ef1c2f9c8c8d2bfffded0113d73e938bef5ef..63564f79d921c04a3273cf5531bedf46e231fda1 100644
--- a/modules/Admin/Language/en/Breadcrumb.php
+++ b/modules/Admin/Language/en/Breadcrumb.php
@@ -16,6 +16,7 @@ return [
     'episodes' => 'episodes',
     'contributors' => 'contributors',
     'pages' => 'pages',
+    'settings' => 'settings',
     'add' => 'add',
     'new' => 'new',
     'edit' => 'edit',
diff --git a/modules/Admin/Language/en/Settings.php b/modules/Admin/Language/en/Settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..8864c87fdb6c18bfd82f39e48c630561885143cc
--- /dev/null
+++ b/modules/Admin/Language/en/Settings.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'title' => 'General settings',
+    'form' => [
+        'site_section_title' => 'Instance',
+        'site_icon' => 'Site icon',
+        'site_icon_delete' => 'Delete site icon',
+        'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.',
+        'site_icon_helper' => 'Icon must be squared with at least 512px wide and tall.',
+        'site_name' => 'Site name',
+        'site_description' => 'Site description',
+        'submit' => 'Save',
+    ],
+];
diff --git a/modules/Admin/Language/fr/AdminNavigation.php b/modules/Admin/Language/fr/AdminNavigation.php
index 357b64ffabadbb2881ed2763257a0b7effe76756..b85b1a30253d84691ff033becc1f97dfe7fa4c85 100644
--- a/modules/Admin/Language/fr/AdminNavigation.php
+++ b/modules/Admin/Language/fr/AdminNavigation.php
@@ -28,6 +28,8 @@ return [
     'pages' => 'Pages',
     'page-list' => 'Toutes les pages',
     'page-create' => 'Créer une page',
+    'settings' => 'Paramètres',
+    'settings-general' => 'Général',
     'account' => [
         'my-account' => 'Mon compte',
         'change-password' => 'Modifier le mot de passe',
diff --git a/modules/Admin/Language/fr/Settings.php b/modules/Admin/Language/fr/Settings.php
new file mode 100644
index 0000000000000000000000000000000000000000..e68c87c7a2f1f477a013da81f408c9204c21721b
--- /dev/null
+++ b/modules/Admin/Language/fr/Settings.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'title' => 'Paramètres généraux',
+    'form' => [
+        'site_section_title' => 'Instance',
+        'site_section_subtitle' => 'configuration de l’instance',
+        'site_icon' => 'Favicon du site',
+        'site_icon_delete' => 'Supprimer la favicon du site',
+        'site_icon_hint' => 'Les favicons sont ce que vous voyez sur les onglets de votre navigateur, dans votre barre de favoris, et lorsque vous ajoutez un site web en raccourci sur des appareils mobiles.',
+        'site_icon_helper' => 'La favicon doit être carrée et avoir au moins 512px de largeur et de hauteur.',
+        'site_name' => 'Titre du site',
+        'site_description' => 'Description du site',
+        'submit' => 'Save',
+    ],
+];
diff --git a/modules/Install/Controllers/InstallController.php b/modules/Install/Controllers/InstallController.php
index 59bad8c901056c40b6dc550a7a32df75de28dbd0..5a65ce4475c05dd9db6d370d455254bba59e3b1e 100644
--- a/modules/Install/Controllers/InstallController.php
+++ b/modules/Install/Controllers/InstallController.php
@@ -243,6 +243,8 @@ class InstallController extends Controller
     {
         $migrations = Services::migrations();
 
+        $migrations->setNamespace('Sparks\Settings')
+            ->latest();
         $migrations->setNamespace('Myth\Auth')
             ->latest();
         $migrations->setNamespace('Modules\Fediverse')
diff --git a/public/favicon.ico b/public/favicon.ico
index b844d1d06dc8c533874fdb40bdb0701700dda75f..9bf9b97aa31acf5e8dc1c93087eaa79b80d60396 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/icon-180.png b/public/icon-180.png
new file mode 100644
index 0000000000000000000000000000000000000000..937c4c6c80ad0926a8fbfc1783d26c76e0698072
Binary files /dev/null and b/public/icon-180.png differ
diff --git a/public/icon-192.png b/public/icon-192.png
new file mode 100644
index 0000000000000000000000000000000000000000..7864f7e9495a68e5e5bc6958d602bab2c4733a2c
Binary files /dev/null and b/public/icon-192.png differ
diff --git a/public/icon-512.png b/public/icon-512.png
new file mode 100644
index 0000000000000000000000000000000000000000..9998e36ae442c3aa2a55834aa093163d5dd05dbd
Binary files /dev/null and b/public/icon-512.png differ
diff --git a/public/icon-64.png b/public/icon-64.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf8d2cf1cc1cb9704de282006a76a1ce86568be7
Binary files /dev/null and b/public/icon-64.png differ
diff --git a/public/icon.png b/public/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c182ad441f3c993ef0d680db2293ebe0018bcb3
Binary files /dev/null and b/public/icon.png differ
diff --git a/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php
index 3b673615abd8278046aebd47181a85382d14e026..17274d51df40ea14d2be7804174adcaf8620176a 100644
--- a/themes/cp_admin/_layout.php
+++ b/themes/cp_admin/_layout.php
@@ -7,7 +7,10 @@
     <title><?= $this->renderSection('title') ?> | Castopod Admin</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="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php
index 0a1a7f410a61c0e302058b6a649fecae852c659e..dd8cb12a4dcfc5d917beac7221ac020ed1ca8e7a 100644
--- a/themes/cp_admin/_sidebar.php
+++ b/themes/cp_admin/_sidebar.php
@@ -22,6 +22,10 @@ $navigation = [
         'items' => ['page-list', 'page-create'],
 
     ],
+    'settings' => [
+        'icon' => 'settings',
+        'items' => ['settings-general'],
+    ],
 ]; ?>
 
 <nav class="flex flex-col flex-1 py-4 overflow-y-auto gap-y-4">
diff --git a/themes/cp_admin/person/edit.php b/themes/cp_admin/person/edit.php
index 49c2ca484d8e939861cb630691b188f69bc15c60..7ce8966e79db141d7e5271d3d80db5776e4d59a9 100644
--- a/themes/cp_admin/person/edit.php
+++ b/themes/cp_admin/person/edit.php
@@ -35,6 +35,7 @@
     label="<?= lang('Person.form.unique_name') ?>"
     hint="<?= lang('Person.form.unique_name_hint') ?>"
     required="true" />
+
 <Forms.Field
     name="information_url"
     label="<?= lang('Person.form.information_url') ?>"
diff --git a/themes/cp_admin/settings/general.php b/themes/cp_admin/settings/general.php
new file mode 100644
index 0000000000000000000000000000000000000000..f48bc581365866c1b2e8eff88154d38c36e7b2e6
--- /dev/null
+++ b/themes/cp_admin/settings/general.php
@@ -0,0 +1,59 @@
+<?= $this->extend('_layout') ?>
+
+<?= $this->section('title') ?>
+<?= lang('Settings.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('pageTitle') ?>
+<?= lang('Settings.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('content') ?>
+
+<form action="<?= route_to('settings-instance') ?>" method="POST" class="flex flex-col max-w-sm gap-y-4" enctype="multipart/form-data">
+<?= csrf_field() ?>
+
+<Forms.Section
+    title="<?= lang('Settings.form.site_section_title') ?>">
+
+    <Forms.Field
+        name="site_name"
+        label="<?= lang('Settings.form.site_name') ?>"
+        value="<?= service('settings')
+    ->get('App.siteName') ?>"
+        required="true" />
+
+    <Forms.Field
+        as="Textarea"
+        name="site_description"
+        label="<?= lang('Settings.form.site_description') ?>"
+        value="<?= service('settings')
+    ->get('App.siteDescription') ?>"
+        required="true"
+        rows="4" />
+
+    <div class="flex items-center">
+        <Forms.Field
+            name="site_icon"
+            type="file"
+            label="<?= lang('Settings.form.site_icon') ?>"
+            hint="<?= lang('Settings.form.site_icon_hint') ?>"
+            helper="<?= lang('Settings.form.site_icon_helper') ?>"
+            accept=".png,.jpeg"
+            class="flex-1"
+            />
+        <?php if (config('App')->siteIcon['ico'] !== service('settings')->get('App.siteIcon')['ico']): ?>
+        <div class="relative ml-2">
+            <a href="<?= route_to('settings-instance-delete-icon') ?>" class="absolute p-1 text-white bg-red-600 border-2 border-black rounded-full hover:bg-red-800 -top-3 -right-3 focus:ring-castopod" title="<?= lang('Settings.form.site_icon_delete') ?>"><?= icon('delete-bin') ?></a>
+            <img src="<?= service('settings')->get('App.siteIcon')['64'] ?>" alt="<?= service('settings')->get('App.siteName') ?> Favicon" class="w-10 h-10" />
+        </div>
+        <?php endif; ?>
+    </div>
+
+    <Button variant="primary" type="submit" class="self-end"><?= lang('Settings.form.submit') ?></Button>
+
+</Forms.Section>
+
+</form>
+
+<?= $this->endSection() ?>
diff --git a/themes/cp_app/_layout.php b/themes/cp_app/_layout.php
index eda77ca64453d3fda0f5dd54efe911b10bf693bc..54afb9f28525111015111e2bbf36285c8f5c87a2 100644
--- a/themes/cp_app/_layout.php
+++ b/themes/cp_app/_layout.php
@@ -6,9 +6,20 @@
 <head>
     <meta charset="UTF-8"/>
     <title><?= $this->renderSection('title') ?></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="description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
+
+    <meta property="og:title" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+    <meta property="og:description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>" />
+    <meta property="og:site_name" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
 
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_app/embed.php b/themes/cp_app/embed.php
index 2817de36ace59259d35a4cdd991a1eb5edf39303..612a5f1f039f191eb7884c62755bbc1adc6573d4 100644
--- a/themes/cp_app/embed.php
+++ b/themes/cp_app/embed.php
@@ -8,7 +8,10 @@
     <meta name="description" content="<?= htmlspecialchars(
         $episode->description,
     ) ?>" />
-    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <link rel="canonical" href="<?= $episode->link ?>" />
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_app/episode/_layout.php b/themes/cp_app/episode/_layout.php
index 8eb6efd87257c49f5b46a8a8d83f0c77f7b95a4e..813c198387aa042ff1192878f1e4125291cb4d80 100644
--- a/themes/cp_app/episode/_layout.php
+++ b/themes/cp_app/episode/_layout.php
@@ -7,7 +7,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= $this->renderSection('meta-tags') ?>
     <?php if ($podcast->payment_pointer): ?>
diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php
index 310f50539e0a760d763aa4b6510daff0634ff6bc..0852e85c054c9fc29b0caf5f4f9382d097913c76 100644
--- a/themes/cp_app/home.php
+++ b/themes/cp_app/home.php
@@ -5,10 +5,23 @@
 
 <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."/>
+    <title><?= service('settings')
+    ->get('App.siteName') ?></title>
+    <meta name="description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
+
+    <meta property="og:title" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+    <meta property="og:description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>" />
+    <meta property="og:site_name" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/map.php b/themes/cp_app/map.php
index e59fcd016888238280ab63da394ba849a88865a9..2838dcea8d49fdf78338e534bf010ce35a61af8f 100644
--- a/themes/cp_app/map.php
+++ b/themes/cp_app/map.php
@@ -8,7 +8,10 @@
     <title><?= lang('Page.map') ?></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="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/page.php b/themes/cp_app/page.php
index b8c0f8e7f4008ef4c9556895fb25f695894d0544..84399887f1c4de6560946e86696fcdcf72680546 100644
--- a/themes/cp_app/page.php
+++ b/themes/cp_app/page.php
@@ -7,7 +7,10 @@
     <meta charset="UTF-8"/>
     <title><?= $page->title ?></title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/podcast/_layout.php b/themes/cp_app/podcast/_layout.php
index 487a58abcf263b3325e280f65afe410e0216976f..8a9c9eea162aa759385caa6f40ff57a65d920941 100644
--- a/themes/cp_app/podcast/_layout.php
+++ b/themes/cp_app/podcast/_layout.php
@@ -7,7 +7,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= $this->renderSection('meta-tags') ?>
     <?php if ($podcast->payment_pointer): ?>
diff --git a/themes/cp_app/podcast/about.php b/themes/cp_app/podcast/about.php
index 7383c93cd0489da648ac9cb8656653e573709a9c..1c80116ca4cf8c4e5dfc97375cead06956441255 100644
--- a/themes/cp_app/podcast/about.php
+++ b/themes/cp_app/podcast/about.php
@@ -9,7 +9,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/activity.php b/themes/cp_app/podcast/activity.php
index f291f25794e028e8ec2d5465cc461f8a6f6f9535..3743d8859b2b4dfdaee1c416182b32a6837f0bfc 100644
--- a/themes/cp_app/podcast/activity.php
+++ b/themes/cp_app/podcast/activity.php
@@ -7,7 +7,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/episodes.php b/themes/cp_app/podcast/episodes.php
index c5a97c9aee1ea31688b7839f23fd3bdbdf0d4b5b..8b6bae0fe4a8193a62302fda6bccf7e381b3b9fb 100644
--- a/themes/cp_app/podcast/episodes.php
+++ b/themes/cp_app/podcast/episodes.php
@@ -7,7 +7,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php
index 473980cf75d1e732aca353b6c9455531d832a1df..abd8888d7796b83bb3c08733b9a3b49b4885d2b3 100644
--- a/themes/cp_app/podcast/follow.php
+++ b/themes/cp_app/podcast/follow.php
@@ -7,8 +7,10 @@
 <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
-    <?= service('vite')->asset('styles/index.css', 'css') ?>
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     
     <title><?= lang('Podcast.followTitle', [
         'actorDisplayName' => $actor->display_name,
diff --git a/themes/cp_app/post/remote_action.php b/themes/cp_app/post/remote_action.php
index 3a885e9ee1a68335ba33760de5f678a0decb854f..6914f04bee26e1d286dba92b6aff101d268b4244 100644
--- a/themes/cp_app/post/remote_action.php
+++ b/themes/cp_app/post/remote_action.php
@@ -5,7 +5,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <title><?= lang('Fediverse.' . $action . '.title', [
         'actorDisplayName' => $post->actor->display_name,
diff --git a/themes/cp_auth/_layout.php b/themes/cp_auth/_layout.php
index b22e49856d76bda71d7c8e88df208f349bfc723e..9ac33873f9bed74c216a1cb71ef51baaca7970bf 100644
--- a/themes/cp_auth/_layout.php
+++ b/themes/cp_auth/_layout.php
@@ -7,7 +7,7 @@
 	<title>Castopod Auth</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="icon" type="image/x-icon" href="/favicon.ico" />
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
 </head>
diff --git a/themes/cp_install/_layout.php b/themes/cp_install/_layout.php
index a3ed84c4769178537b648be77a584af5842a7ab2..affa0827c6febb4ef71766b4e3dda44e6b067621 100644
--- a/themes/cp_install/_layout.php
+++ b/themes/cp_install/_layout.php
@@ -6,7 +6,10 @@
     <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="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')