diff --git a/api/funkwhale_api/common/dynamic_preferences_registry.py b/api/funkwhale_api/common/dynamic_preferences_registry.py
index 2374de7c79fe841ae63d8c18354335cf6fd022b2..15b182671bbf386b401eeb541c3839889342e29d 100644
--- a/api/funkwhale_api/common/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/common/dynamic_preferences_registry.py
@@ -16,5 +16,5 @@ class APIAutenticationRequired(
     help_text = (
         'If disabled, anonymous users will be able to query the API'
         'and access music data (as well as other data exposed in the API '
-        'without specific permissions)'
+        'without specific permissions).'
     )
diff --git a/api/funkwhale_api/federation/dynamic_preferences_registry.py b/api/funkwhale_api/federation/dynamic_preferences_registry.py
index e86b9f6f2b8b30da1c82145ef288e591449aa9f3..8b1b2b03f9eb00f0eac1d467c099baf66d72d67d 100644
--- a/api/funkwhale_api/federation/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/federation/dynamic_preferences_registry.py
@@ -19,6 +19,9 @@ class MusicCacheDuration(types.IntPreference):
         'locally? Federated files that were not listened in this interval '
         'will be erased and refetched from the remote on the next listening.'
     )
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -29,7 +32,7 @@ class Enabled(preferences.DefaultFromSettingMixin, types.BooleanPreference):
     verbose_name = 'Federation enabled'
     help_text = (
         'Use this setting to enable or disable federation logic and API'
-        ' globally'
+        ' globally.'
     )
 
 
@@ -41,8 +44,11 @@ class CollectionPageSize(
     setting = 'FEDERATION_COLLECTION_PAGE_SIZE'
     verbose_name = 'Federation collection page size'
     help_text = (
-        'How much items to display in ActivityPub collections'
+        'How much items to display in ActivityPub collections.'
     )
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -54,8 +60,11 @@ class ActorFetchDelay(
     verbose_name = 'Federation actor fetch delay'
     help_text = (
         'How much minutes to wait before refetching actors on '
-        'request authentication'
+        'request authentication.'
     )
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -66,6 +75,6 @@ class MusicNeedsApproval(
     setting = 'FEDERATION_MUSIC_NEEDS_APPROVAL'
     verbose_name = 'Federation music needs approval'
     help_text = (
-        'When true, other federation actors will require your approval'
+        'When true, other federation actors will need your approval'
         ' before being able to browse your library.'
     )
diff --git a/api/funkwhale_api/instance/dynamic_preferences_registry.py b/api/funkwhale_api/instance/dynamic_preferences_registry.py
index 20679fd3dcff4cec208477487b6d245219abc273..8ccf80dd93448b4f2512ec2109cda32beaa33bf7 100644
--- a/api/funkwhale_api/instance/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/instance/dynamic_preferences_registry.py
@@ -13,8 +13,11 @@ class InstanceName(types.StringPreference):
     section = instance
     name = 'name'
     default = ''
-    help_text = 'Instance public name'
-    verbose_name = 'The public name of your instance'
+    verbose_name = 'Public name'
+    help_text = 'The public name of your instance, displayed in the about page.'
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -23,7 +26,11 @@ class InstanceShortDescription(types.StringPreference):
     section = instance
     name = 'short_description'
     default = ''
-    verbose_name = 'Instance succinct description'
+    verbose_name = 'Short description'
+    help_text = 'Instance succinct description, displayed in the about page.'
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -31,31 +38,31 @@ class InstanceLongDescription(types.StringPreference):
     show_in_api = True
     section = instance
     name = 'long_description'
+    verbose_name = 'Long description'
     default = ''
-    help_text = 'Instance long description (markdown allowed)'
+    help_text = 'Instance long description, displayed in the about page (markdown allowed).'
+    widget = widgets.Textarea
     field_kwargs = {
-        'widget': widgets.Textarea
+        'required': False,
     }
 
+
 @global_preferences_registry.register
 class RavenDSN(types.StringPreference):
     show_in_api = True
     section = raven
     name = 'front_dsn'
     default = 'https://9e0562d46b09442bb8f6844e50cbca2b@sentry.eliotberriot.com/4'
-    verbose_name = (
-        'A raven DSN key used to report front-ent errors to '
-        'a sentry instance'
-    )
+    verbose_name = 'Raven DSN key (front-end)'
+
     help_text = (
-        'Keeping the default one will report errors to funkwhale developers'
+        'A Raven DSN key used to report front-ent errors to '
+        'a sentry instance. Keeping the default one will report errors to '
+        'Funkwhale developers.'
     )
-
-
-SENTRY_HELP_TEXT = (
-    'Error reporting is disabled by default but you can enable it if'
-    ' you want to help us improve funkwhale'
-)
+    field_kwargs = {
+        'required': False,
+    }
 
 
 @global_preferences_registry.register
@@ -65,8 +72,7 @@ class RavenEnabled(types.BooleanPreference):
     name = 'front_enabled'
     default = False
     verbose_name = (
-        'Wether error reporting to a Sentry instance using raven is enabled'
-        ' for front-end errors'
+        'Report front-end errors with Raven'
     )
 
 
@@ -78,7 +84,7 @@ class InstanceNodeinfoEnabled(types.BooleanPreference):
     default = True
     verbose_name = 'Enable nodeinfo endpoint'
     help_text = (
-        'This endpoint is needed for your about page to work.'
+        'This endpoint is needed for your about page to work. '
         'It\'s also helpful for the various monitoring '
         'tools that map and analyzize the fediverse, '
         'but you can disable it completely if needed.'
@@ -91,10 +97,10 @@ class InstanceNodeinfoPrivate(types.BooleanPreference):
     section = instance
     name = 'nodeinfo_private'
     default = False
-    verbose_name = 'Enable nodeinfo endpoint'
+    verbose_name = 'Private mode in nodeinfo'
     help_text = (
-        'Indicate in the nodeinfo endpoint that you do not want your instance'
-        'to be tracked by third-party services.'
+        'Indicate in the nodeinfo endpoint that you do not want your instance '
+        'to be tracked by third-party services. '
         'There is no guarantee these tools will honor this setting though.'
     )
 
@@ -107,6 +113,6 @@ class InstanceNodeinfoStatsEnabled(types.BooleanPreference):
     default = True
     verbose_name = 'Enable usage and library stats in nodeinfo endpoint'
     help_text = (
-        'Disable this f you don\'t want to share usage and library statistics'
+        'Disable this if you don\'t want to share usage and library statistics '
         'in the nodeinfo endpoint but don\'t want to disable it completely.'
     )
diff --git a/api/funkwhale_api/instance/urls.py b/api/funkwhale_api/instance/urls.py
index f506488fc4db7819da6aae5d5c79fe33e8a9af5c..7992842c030c636057ed13236da282febda9cc4e 100644
--- a/api/funkwhale_api/instance/urls.py
+++ b/api/funkwhale_api/instance/urls.py
@@ -1,9 +1,11 @@
 from django.conf.urls import url
+from rest_framework import routers
 
 from . import views
-
+admin_router = routers.SimpleRouter()
+admin_router.register(r'admin/settings', views.AdminSettings, 'admin-settings')
 
 urlpatterns = [
     url(r'^nodeinfo/2.0/$', views.NodeInfo.as_view(), name='nodeinfo-2.0'),
     url(r'^settings/$', views.InstanceSettings.as_view(), name='settings'),
-]
+] + admin_router.urls
diff --git a/api/funkwhale_api/instance/views.py b/api/funkwhale_api/instance/views.py
index 5953ca555a3081d5e58a1d60da1d3dec58279e3b..e6725e24846500f86bfbf9105d55b2a6780dc5dd 100644
--- a/api/funkwhale_api/instance/views.py
+++ b/api/funkwhale_api/instance/views.py
@@ -2,6 +2,7 @@ from rest_framework import views
 from rest_framework.response import Response
 
 from dynamic_preferences.api import serializers
+from dynamic_preferences.api import viewsets as preferences_viewsets
 from dynamic_preferences.registries import global_preferences_registry
 
 from funkwhale_api.common import preferences
@@ -15,6 +16,10 @@ NODEINFO_2_CONTENT_TYPE = (
 )
 
 
+class AdminSettings(preferences_viewsets.GlobalPreferencesViewSet):
+    pagination_class = None
+
+
 class InstanceSettings(views.APIView):
     permission_classes = []
     authentication_classes = []
diff --git a/api/funkwhale_api/playlists/dynamic_preferences_registry.py b/api/funkwhale_api/playlists/dynamic_preferences_registry.py
index 21140fa1495adb734aa64e41be4bae218ba74304..b717177a2368ccfb267f651bd76def8c6e9fc443 100644
--- a/api/funkwhale_api/playlists/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/playlists/dynamic_preferences_registry.py
@@ -13,3 +13,6 @@ class MaxTracks(preferences.DefaultFromSettingMixin, types.IntegerPreference):
     name = 'max_tracks'
     verbose_name = 'Max tracks per playlist'
     setting = 'PLAYLISTS_MAX_TRACKS'
+    field_kwargs = {
+        'required': False,
+    }
diff --git a/api/funkwhale_api/providers/acoustid/dynamic_preferences_registry.py b/api/funkwhale_api/providers/acoustid/dynamic_preferences_registry.py
index da785df4065aff76cf8d1a4e9d19967b0b7bfa9c..33c9643b00b4ec96665a7e8cbcfae13098d13a04 100644
--- a/api/funkwhale_api/providers/acoustid/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/providers/acoustid/dynamic_preferences_registry.py
@@ -1,3 +1,5 @@
+from django import forms
+
 from dynamic_preferences.types import StringPreference, Section
 from dynamic_preferences.registries import global_preferences_registry
 
@@ -11,3 +13,7 @@ class APIKey(StringPreference):
     default = ''
     verbose_name = 'Acoustid API key'
     help_text = 'The API key used to query AcoustID. Get one at https://acoustid.org/new-application.'
+    widget = forms.PasswordInput
+    field_kwargs = {
+        'required': False,
+    }
diff --git a/api/funkwhale_api/providers/youtube/dynamic_preferences_registry.py b/api/funkwhale_api/providers/youtube/dynamic_preferences_registry.py
index fc7f7d793e5a535f344d63678f418b0736ae2862..ac5fc4bde29a313429b7644b51846fa3e33b0465 100644
--- a/api/funkwhale_api/providers/youtube/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/providers/youtube/dynamic_preferences_registry.py
@@ -1,3 +1,5 @@
+from django import forms
+
 from dynamic_preferences.types import StringPreference, Section
 from dynamic_preferences.registries import global_preferences_registry
 
@@ -11,3 +13,7 @@ class APIKey(StringPreference):
     default = 'CHANGEME'
     verbose_name = 'YouTube API key'
     help_text = 'The API key used to query YouTube. Get one at https://console.developers.google.com/.'
+    widget = forms.PasswordInput
+    field_kwargs = {
+        'required': False,
+    }
diff --git a/api/funkwhale_api/users/dynamic_preferences_registry.py b/api/funkwhale_api/users/dynamic_preferences_registry.py
index 16d79da143cb3139f9a92137044b6092288e1b40..4f736053088df4fad3ccd804744c8dec826d388f 100644
--- a/api/funkwhale_api/users/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/users/dynamic_preferences_registry.py
@@ -10,6 +10,7 @@ class RegistrationEnabled(types.BooleanPreference):
     section = users
     name = 'registration_enabled'
     default = False
-    verbose_name = (
-        'Can visitors open a new account on this instance?'
+    verbose_name = 'Open registrations to new users'
+    help_text = (
+        'When enabled, new users will be able to register on this instance.'
     )
diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py
index f067a2a8b44b4bfbd61b8f7af86829301d178da0..8273507c49bb23f1986b6b691fe90cc1fc8fea45 100644
--- a/api/funkwhale_api/users/models.py
+++ b/api/funkwhale_api/users/models.py
@@ -6,7 +6,7 @@ import os
 import uuid
 
 from django.conf import settings
-from django.contrib.auth.models import AbstractUser
+from django.contrib.auth.models import AbstractUser, Permission
 from django.urls import reverse
 from django.db import models
 from django.utils.encoding import python_2_unicode_compatible
@@ -55,6 +55,10 @@ class User(AbstractUser):
     def __str__(self):
         return self.username
 
+    def add_permission(self, codename):
+        p = Permission.objects.get(codename=codename)
+        self.user_permissions.add(p)
+
     def get_absolute_url(self):
         return reverse('users:detail', kwargs={'username': self.username})
 
diff --git a/api/tests/instance/test_views.py b/api/tests/instance/test_views.py
index 468c0ddae9de440b3edce7fd65fdc57c6ead8fff..6d8dcac3eebe1470da291a783bb7ad97a8b0c127 100644
--- a/api/tests/instance/test_views.py
+++ b/api/tests/instance/test_views.py
@@ -21,3 +21,31 @@ def test_nodeinfo_endpoint_disabled(db, api_client, preferences):
     response = api_client.get(url)
 
     assert response.status_code == 404
+
+
+def test_settings_only_list_public_settings(db, api_client, preferences):
+    url = reverse('api:v1:instance:settings')
+    response = api_client.get(url)
+
+    for conf in response.data:
+        p = preferences.model.objects.get(
+            section=conf['section'], name=conf['name'])
+        assert p.preference.show_in_api is True
+
+
+def test_admin_settings_restrict_access(db, logged_in_api_client, preferences):
+    url = reverse('api:v1:instance:admin-settings-list')
+    response = logged_in_api_client.get(url)
+
+    assert response.status_code == 403
+
+
+def test_admin_settings_correct_permission(
+        db, logged_in_api_client, preferences):
+    user = logged_in_api_client.user
+    user.add_permission('change_globalpreferencemodel')
+    url = reverse('api:v1:instance:admin-settings-list')
+    response = logged_in_api_client.get(url)
+
+    assert response.status_code == 200
+    assert len(response.data) == len(preferences.all())
diff --git a/changes/changelog.d/206.feature b/changes/changelog.d/206.feature
new file mode 100644
index 0000000000000000000000000000000000000000..b334554fe0a3243ae7f85f3386ed714f6ed8a870
--- /dev/null
+++ b/changes/changelog.d/206.feature
@@ -0,0 +1,17 @@
+We now have a brand new instance settings interface in the front-end (#206)
+
+
+Instance settings interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Prior to this release, the only way to update instance settings (such as
+instance description, signup policy, federation configuration, etc.) was using
+the admin interface provided by Django (the back-end framework which power the API).
+
+This interface worked, but was not really-user friendly and intuitive.
+
+Starting from this release, we now offer a dedicated interface directly
+in the front-end. You can view and edit all your instance settings from here,
+assuming you have the required permissions.
+
+This interface is available at ``/manage/settings` and via link in the sidebar.
diff --git a/docs/configuration.rst b/docs/configuration.rst
index bbc658e087977e5eaa7c3f53598fdad99d68b4aa..b7df2db42079304fe9956a5460ea6f9beb4e746d 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -27,15 +27,24 @@ Those settings are stored in database and do not require a restart of your
 instance after modification. They typically relate to higher level configuration,
 such your instance description, signup policy and so on.
 
-There is no polished interface for those settings, yet, but you can view update
-them using the administration interface provided by Django (the framework funkwhale is built on).
-
-The URL should be ``/api/admin/dynamic_preferences/globalpreferencemodel/`` (prepend your domain in front of it, of course).
+You can edit those settings directly from the web application, assuming
+you have the required permissions. The URL is ``/manage/settings``, and
+you will also find a link to this page in the sidebar.
 
 If you plan to use acoustid and external imports
 (e.g. with the youtube backends), you should edit the corresponding
 settings in this interface.
 
+.. note::
+
+    If you have any issue with the web application, a management interface is also
+    available for those settings from Django's administration interface. It's
+    less user friendly, though, and we recommend you use the web app interface
+    whenever possible.
+
+    The URL should be ``/api/admin/dynamic_preferences/globalpreferencemodel/`` (prepend your domain in front of it, of course).
+
+
 Configuration reference
 -----------------------
 
diff --git a/front/src/components/About.vue b/front/src/components/About.vue
index 524191250cf920fdbe4991381f827c1e50dd5ecd..b0ae67ef7ae554aa70a2ed6cc595b45fea81b32d 100644
--- a/front/src/components/About.vue
+++ b/front/src/components/About.vue
@@ -13,6 +13,12 @@
       <p v-if="!instance.short_description.value && !instance.long_description.value">
         {{ $t('Unfortunately, owners of this instance did not yet take the time to complete this page.') }}
       </p>
+      <router-link
+        class="ui button"
+        v-if="$store.state.auth.availablePermissions['settings.change']"
+        :to="{path: '/manage/settings', hash: 'instance'}">
+        <i class="pencil icon"></i>{{ $t('Edit instance info') }}
+      </router-link>
       <div
         v-if="instance.short_description.value"
         class="ui middle aligned stackable text container">
diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue
index 97c743bbe804a5ca64bfe39ce69ad5b725745365..9fbc5605c8e13923379e879b4b1a6b3322d14333 100644
--- a/front/src/components/Sidebar.vue
+++ b/front/src/components/Sidebar.vue
@@ -78,6 +78,12 @@
                 :title="$t('Pending follow requests')">
                 {{ notifications.federation }}</div>
             </router-link>
+            <router-link
+              class="item"
+              v-if="$store.state.auth.availablePermissions['settings.change']"
+              :to="{path: '/manage/settings'}">
+              <i class="settings icon"></i>{{ $t('Settings') }}
+            </router-link>
           </div>
         </div>
       </div>
@@ -217,7 +223,6 @@ export default {
       }
       let self = this
       axios.get('requests/import-requests/', {params: {status: 'pending'}}).then(response => {
-        console.log('YOLo')
         self.notifications.importRequests = response.data.count
       })
     },
@@ -256,7 +261,6 @@ export default {
     },
     '$store.state.availablePermissions': {
       handler () {
-        console.log('YOLO')
         this.fetchNotificationsCount()
       },
       deep: true
diff --git a/front/src/components/admin/SettingsGroup.vue b/front/src/components/admin/SettingsGroup.vue
new file mode 100644
index 0000000000000000000000000000000000000000..255f04488973fbc4eb5c1ecc5e97418294c258ff
--- /dev/null
+++ b/front/src/components/admin/SettingsGroup.vue
@@ -0,0 +1,120 @@
+<template>
+  <form :id="group.id" class="ui form" @submit.prevent="save">
+    <div class="ui divider" />
+    <h3 class="ui header">{{ group.label }}</h3>
+    <div v-if="errors.length > 0" class="ui negative message">
+      <div class="header">{{ $t('Error while saving settings') }}</div>
+      <ul class="list">
+        <li v-for="error in errors">{{ error }}</li>
+      </ul>
+    </div>
+    <div v-if="result" class="ui positive message">
+      {{ $t('Settings updated successfully.') }}
+    </div>
+    <p v-if="group.help">{{ group.help }}</p>
+    <div v-for="setting in settings" class="ui field">
+      <template v-if="setting.field.widget.class !== 'CheckboxInput'">
+        <label :for="setting.identifier">{{ setting.verbose_name }}</label>
+        <p v-if="setting.help_text">{{ setting.help_text }}</p>
+      </template>
+      <input
+        :id="setting.identifier"
+        v-if="setting.field.widget.class === 'PasswordInput'"
+        type="password"
+        class="ui input"
+        v-model="values[setting.identifier]" />
+      <input
+        :id="setting.identifier"
+        v-if="setting.field.widget.class === 'TextInput'"
+        type="text"
+        class="ui input"
+        v-model="values[setting.identifier]" />
+      <input
+        :id="setting.identifier"
+        v-if="setting.field.class === 'IntegerField'"
+        type="number"
+        class="ui input"
+        v-model.number="values[setting.identifier]" />
+      <textarea
+        :id="setting.identifier"
+        v-else-if="setting.field.widget.class === 'Textarea'"
+        type="text"
+        class="ui input"
+        v-model="values[setting.identifier]" />
+      <div v-else-if="setting.field.widget.class === 'CheckboxInput'" class="ui toggle checkbox">
+        <input
+          :id="setting.identifier"
+          :name="setting.identifier"
+          v-model="values[setting.identifier]"
+          type="checkbox" />
+        <label :for="setting.identifier">{{ setting.verbose_name }}</label>
+        <p v-if="setting.help_text">{{ setting.help_text }}</p>
+      </div>
+    </div>
+    <button
+      type="submit"
+      :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']">
+        {{ $t('Save') }}
+    </button>
+  </form>
+</template>
+
+<script>
+import axios from 'axios'
+
+export default {
+  props: {
+    group: {type: Object, required: true},
+    settingsData: {type: Array, required: true}
+  },
+  data () {
+    return {
+      values: {},
+      result: null,
+      errors: [],
+      isLoading: false
+    }
+  },
+  created () {
+    let self = this
+    this.settings.forEach(e => {
+      self.values[e.identifier] = e.value
+    })
+  },
+  methods: {
+    save () {
+      let self = this
+      this.isLoading = true
+      self.errors = []
+      self.result = null
+      axios.post('instance/admin/settings/bulk/', self.values).then((response) => {
+        self.result = true
+        self.isLoading = false
+        self.$store.dispatch('instance/fetchSettings')
+      }, error => {
+        self.isLoading = false
+        self.errors = error.backendErrors
+      })
+    }
+  },
+  computed: {
+    settings () {
+      let byIdentifier = {}
+      this.settingsData.forEach(e => {
+        byIdentifier[e.identifier] = e
+      })
+      return this.group.settings.map(e => {
+        return byIdentifier[e]
+      })
+    }
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+
+.ui.checkbox p {
+  margin-top: 1rem;
+}
+</style>
diff --git a/front/src/main.js b/front/src/main.js
index 5481615f2006025cea7e009dc9ddd8a49b97623f..2e92fbbd2243e20f567f47dcbcc5e5f3c7937659 100644
--- a/front/src/main.js
+++ b/front/src/main.js
@@ -35,8 +35,26 @@ Vue.use(VueMasonryPlugin)
 Vue.use(VueLazyload)
 Vue.config.productionTip = false
 Vue.directive('title', {
-  inserted: (el, binding) => { document.title = binding.value + ' - Funkwhale' },
-  updated: (el, binding) => { document.title = binding.value + ' - Funkwhale' }
+  inserted: (el, binding) => {
+    let parts = []
+    let instanceName = store.state.instance.settings.instance.name.value
+    if (instanceName.length === 0) {
+      instanceName = 'Funkwhale'
+    }
+    parts.unshift(instanceName)
+    parts.unshift(binding.value)
+    document.title = parts.join(' - ')
+  },
+  updated: (el, binding) => {
+    let parts = []
+    let instanceName = store.state.instance.settings.instance.name.value
+    if (instanceName.length === 0) {
+      instanceName = 'Funkwhale'
+    }
+    parts.unshift(instanceName)
+    parts.unshift(binding.value)
+    document.title = parts.join(' - ')
+  }
 })
 
 axios.defaults.baseURL = config.API_URL
diff --git a/front/src/router/index.js b/front/src/router/index.js
index b1e208023335945f42c7b255aa05ebaffeac5e2b..f71dab7f92decf05f5df0ca2129207bf7830fb48 100644
--- a/front/src/router/index.js
+++ b/front/src/router/index.js
@@ -28,6 +28,7 @@ import RequestsList from '@/components/requests/RequestsList'
 import PlaylistDetail from '@/views/playlists/Detail'
 import PlaylistList from '@/views/playlists/List'
 import Favorites from '@/components/favorites/List'
+import AdminSettings from '@/views/admin/Settings'
 import FederationBase from '@/views/federation/Base'
 import FederationScan from '@/views/federation/Scan'
 import FederationLibraryDetail from '@/views/federation/LibraryDetail'
@@ -117,6 +118,11 @@ export default new Router({
         defaultPaginateBy: route.query.paginateBy
       })
     },
+    {
+      path: '/manage/settings',
+      name: 'manage.settings',
+      component: AdminSettings
+    },
     {
       path: '/manage/federation',
       component: FederationBase,
diff --git a/front/src/views/admin/Settings.vue b/front/src/views/admin/Settings.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7174ab516c1e438d0aa09b0491e803b26f5f4316
--- /dev/null
+++ b/front/src/views/admin/Settings.vue
@@ -0,0 +1,155 @@
+<template>
+  <div class="main pusher"  v-title="$t('Instance settings')">
+    <div class="ui vertical stripe segment">
+      <div class="ui text container">
+        <div :class="['ui', {'loading': isLoading}, 'form']"></div>
+        <div id="settings-grid" v-if="settingsData" class="ui grid">
+          <div class="twelve wide stretched column">
+            <settings-group
+              :settings-data="settingsData"
+              :group="group"
+              :key="group.title"
+              v-for="group in groups" />
+          </div>
+          <div class="four wide column">
+            <div class="ui sticky vertical secondary menu">
+              <div class="header item">{{ $t('Sections') }}</div>
+              <a :class="['menu', {active: group.id === current}, 'item']"
+                @click.prevent="scrollTo(group.id)"
+                :href="'#' + group.id"
+                v-for="group in groups">{{ group.label }}</a>
+            </div>
+          </div>
+        </div>
+
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+import $ from 'jquery'
+
+import SettingsGroup from '@/components/admin/SettingsGroup'
+
+export default {
+  components: {
+    SettingsGroup
+  },
+  data () {
+    return {
+      isLoading: false,
+      settingsData: null,
+      current: null
+    }
+  },
+  created () {
+    let self = this
+    this.fetchSettings().then(r => {
+      self.$nextTick(() => {
+        if (self.$store.state.route.hash) {
+          self.scrollTo(self.$store.state.route.hash.substr(1))
+        }
+      })
+    })
+  },
+  methods: {
+    scrollTo (id) {
+      console.log(id, 'hello')
+      this.current = id
+      document.getElementById(id).scrollIntoView()
+    },
+    fetchSettings () {
+      let self = this
+      self.isLoading = true
+      return axios.get('instance/admin/settings/').then((response) => {
+        self.settingsData = response.data
+        self.isLoading = false
+      })
+    }
+  },
+  computed: {
+    groups () {
+      return [
+        {
+          label: this.$t('Instance information'),
+          id: 'instance',
+          settings: [
+            'instance__name',
+            'instance__short_description',
+            'instance__long_description'
+          ]
+        },
+        {
+          label: this.$t('Users'),
+          id: 'users',
+          settings: [
+            'users__registration_enabled',
+            'common__api_authentication_required'
+          ]
+        },
+        {
+          label: this.$t('Imports'),
+          id: 'imports',
+          settings: [
+            'providers_youtube__api_key',
+            'providers_acoustid__api_key'
+          ]
+        },
+        {
+          label: this.$t('Playlists'),
+          id: 'playlists',
+          settings: [
+            'playlists__max_tracks'
+          ]
+        },
+        {
+          label: this.$t('Federation'),
+          id: 'federation',
+          settings: [
+            'federation__enabled',
+            'federation__music_needs_approval',
+            'federation__collection_page_size',
+            'federation__music_cache_duration',
+            'federation__actor_fetch_delay'
+          ]
+        },
+        {
+          label: this.$t('Subsonic'),
+          id: 'subsonic',
+          settings: [
+            'subsonic__enabled'
+          ]
+        },
+        {
+          label: this.$t('Statistics'),
+          id: 'statistics',
+          settings: [
+            'instance__nodeinfo_enabled',
+            'instance__nodeinfo_stats_enabled',
+            'instance__nodeinfo_private'
+          ]
+        },
+        {
+          label: this.$t('Error reporting'),
+          id: 'reporting',
+          settings: [
+            'raven__front_enabled',
+            'raven__front_dsn'
+
+          ]
+        }
+      ]
+    }
+  },
+  watch: {
+    settingsData () {
+      let self = this
+      this.$nextTick(() => {
+        $(self.$el).find('.sticky').sticky({context: '#settings-grid'})
+      })
+    }
+  }
+}
+</script>
diff --git a/front/src/views/playlists/List.vue b/front/src/views/playlists/List.vue
index 32ee5aafaa9d28e34d1c824f479c6b0efea0447f..5001fb14db9db32bd129e0fdcefa3a04f60a848b 100644
--- a/front/src/views/playlists/List.vue
+++ b/front/src/views/playlists/List.vue
@@ -76,7 +76,6 @@ export default {
     Pagination
   },
   data () {
-    console.log('YOLO', this.$t)
     let defaultOrdering = this.getOrderingFromString(this.defaultOrdering || '-creation_date')
     return {
       isLoading: true,