diff --git a/api/funkwhale_api/manage/filters.py b/api/funkwhale_api/manage/filters.py
index 984b83133734e81a87194de73016a4f0ca5ee11f..de12ab1ab9188ca5b1e548dbbe20084690a41de8 100644
--- a/api/funkwhale_api/manage/filters.py
+++ b/api/funkwhale_api/manage/filters.py
@@ -235,12 +235,23 @@ class ManageUploadFilterSet(filters.FilterSet):
         ]
 
 
+def filter_allowed(queryset, name, value):
+    """
+    If value=false, we want to include object with value=null as well
+    """
+    if value:
+        return queryset.filter(allowed=True)
+    else:
+        return queryset.filter(Q(allowed=False) | Q(allowed__isnull=True))
+
+
 class ManageDomainFilterSet(filters.FilterSet):
     q = fields.SearchFilter(search_fields=["name"])
+    allowed = filters.BooleanFilter(method=filter_allowed)
 
     class Meta:
         model = federation_models.Domain
-        fields = ["name"]
+        fields = ["name", "allowed"]
 
 
 class ManageActorFilterSet(filters.FilterSet):
diff --git a/api/funkwhale_api/manage/serializers.py b/api/funkwhale_api/manage/serializers.py
index 25f8c01dbbf46e572eb5d712408c59202515627d..c72e015bf97095c6206e08c343ea96b471ce3697 100644
--- a/api/funkwhale_api/manage/serializers.py
+++ b/api/funkwhale_api/manage/serializers.py
@@ -152,7 +152,11 @@ class ManageDomainUpdateSerializer(ManageDomainSerializer):
 
 
 class ManageDomainActionSerializer(common_serializers.ActionSerializer):
-    actions = [common_serializers.Action("purge", allow_all=False)]
+    actions = [
+        common_serializers.Action("purge", allow_all=False),
+        common_serializers.Action("allow_list_add", allow_all=True),
+        common_serializers.Action("allow_list_remove", allow_all=True),
+    ]
     filterset_class = filters.ManageDomainFilterSet
     pk_field = "name"
 
@@ -161,6 +165,14 @@ class ManageDomainActionSerializer(common_serializers.ActionSerializer):
         ids = objects.values_list("pk", flat=True)
         common_utils.on_commit(federation_tasks.purge_actors.delay, domains=list(ids))
 
+    @transaction.atomic
+    def handle_allow_list_add(self, objects):
+        objects.update(allowed=True)
+
+    @transaction.atomic
+    def handle_allow_list_remove(self, objects):
+        objects.update(allowed=False)
+
 
 class ManageBaseActorSerializer(serializers.ModelSerializer):
     class Meta:
diff --git a/api/funkwhale_api/moderation/dynamic_preferences_registry.py b/api/funkwhale_api/moderation/dynamic_preferences_registry.py
index 8d8237cbb4231728021316eacf4eacad00436b14..04a732f4d4863a97d52e1401d0d921cc042c9eeb 100644
--- a/api/funkwhale_api/moderation/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/moderation/dynamic_preferences_registry.py
@@ -19,8 +19,8 @@ class AllowListPublic(types.BooleanPreference):
     name = "allow_list_public"
     verbose_name = "Publish your allowed-domains list"
     help_text = (
-        "If enabled, everyone will be able to retrieve the list of domains you allowed. ",
+        "If enabled, everyone will be able to retrieve the list of domains you allowed. "
         "This is useful on open setups, to help people decide if they want to join your pod, or to "
-        "make your moderation policy public.",
+        "make your moderation policy public."
     )
     default = False
diff --git a/api/tests/manage/test_serializers.py b/api/tests/manage/test_serializers.py
index cfbb175171924cb8a05e4a2bdf8de1f3885eab6c..e621bf14c37d19e1dac19220c7033e47692d5e5b 100644
--- a/api/tests/manage/test_serializers.py
+++ b/api/tests/manage/test_serializers.py
@@ -176,6 +176,26 @@ def test_manage_domain_action_purge(factories, mocker):
     )
 
 
+def test_manage_domain_action_allow_list_add(factories, mocker):
+    domains = factories["federation.Domain"].create_batch(size=3, allowed=False)
+    s = serializers.ManageDomainActionSerializer(queryset=None)
+    s.handle_allow_list_add(domains[0].__class__.objects.all())
+
+    for domain in domains:
+        domain.refresh_from_db()
+        assert domain.allowed is True
+
+
+def test_manage_domain_action_allow_list_remove(factories, mocker):
+    domains = factories["federation.Domain"].create_batch(size=3, allowed=True)
+    s = serializers.ManageDomainActionSerializer(queryset=None)
+    s.handle_allow_list_remove(domains[0].__class__.objects.all())
+
+    for domain in domains:
+        domain.refresh_from_db()
+        assert domain.allowed is False
+
+
 @pytest.mark.parametrize(
     "param,expected_only", [("block_all", []), ("reject_media", ["media"])]
 )
diff --git a/front/src/components/manage/moderation/DomainsTable.vue b/front/src/components/manage/moderation/DomainsTable.vue
index 544d91156f3101236b8395bec133b9248d2d112a..089b7288e9b50554ff7a312058513c5e999d3ec1 100644
--- a/front/src/components/manage/moderation/DomainsTable.vue
+++ b/front/src/components/manage/moderation/DomainsTable.vue
@@ -6,6 +6,14 @@
           <label><translate translate-context="Content/Search/Input.Label/Noun">Search</translate></label>
           <input name="search" type="text" v-model="search" :placeholder="labels.searchPlaceholder" />
         </div>
+        <div class="field" v-if="allowListEnabled">
+          <label><translate translate-context="Content/Moderation/*/Adjective">Is present on allow-list</translate></label>
+          <select class="ui dropdown" v-model="allowed">
+            <option :value="null"><translate translate-context="*/*/*">All</translate></option>
+            <option :value="true"><translate translate-context="*/*/*">Yes</translate></option>
+            <option :value="false"><translate translate-context="*/*/*">No</translate></option>
+          </select>
+        </div>
         <div class="field">
           <label><translate translate-context="Content/Search/Dropdown.Label/Noun">Ordering</translate></label>
           <select class="ui dropdown" v-model="ordering">
@@ -44,7 +52,10 @@
         </template>
         <template slot="row-cells" slot-scope="scope">
           <td>
-            <router-link :to="{name: 'manage.moderation.domains.detail', params: {id: scope.obj.name }}">{{ scope.obj.name }}</router-link>
+            <router-link :to="{name: 'manage.moderation.domains.detail', params: {id: scope.obj.name }}">
+              {{ scope.obj.name }}
+              <i v-if="allowListEnabled && scope.obj.allowed" class="green check icon" :title="labels.allowListTitle"></i>
+            </router-link>
           </td>
           <td>
             {{ scope.obj.actors_count }}
@@ -93,7 +104,8 @@ import TranslationsMixin from '@/components/mixins/Translations'
 export default {
   mixins: [OrderingMixin, TranslationsMixin],
   props: {
-    filters: {type: Object, required: false}
+    filters: {type: Object, required: false},
+    allowListEnabled: {type: Boolean, default: false},
   },
   components: {
     Pagination,
@@ -108,6 +120,7 @@ export default {
       page: 1,
       paginateBy: 50,
       search: '',
+      allowed: null,
       orderingDirection: defaultOrdering.direction || '+',
       ordering: defaultOrdering.field,
       orderingOptions: [
@@ -124,12 +137,16 @@ export default {
   },
   methods: {
     fetchData () {
-      let params = _.merge({
+      let baseFilters = {
         'page': this.page,
         'page_size': this.paginateBy,
         'q': this.search,
-        'ordering': this.getOrderingAsString()
-      }, this.filters)
+        'ordering': this.getOrderingAsString(),
+      }
+      if (this.allowed !== null) {
+        baseFilters.allowed = this.allowed
+      }
+      let params = _.merge(baseFilters, this.filters)
       let self = this
       self.isLoading = true
       self.checked = []
@@ -148,7 +165,8 @@ export default {
   computed: {
     labels () {
       return {
-        searchPlaceholder: this.$pgettext('Content/Search/Input.Placeholder', 'Search by name…')
+        searchPlaceholder: this.$pgettext('Content/Search/Input.Placeholder', 'Search by name…'),
+        allowListTitle: this.$pgettext('Content/Moderation/Popup', 'This domain is present in your allow-list'),
       }
     },
     actionFilters () {
@@ -167,7 +185,21 @@ export default {
           name: 'purge',
           label: this.$pgettext('*/*/*/Verb', 'Purge'),
           isDangerous: true
-        }
+        },
+        {
+          name: 'allow_list_add',
+          label: this.$pgettext('Content/Moderation/Action/Verb', 'Add to allow-list'),
+          filterCheckable: (obj) => {
+            return !obj.allowed
+          }
+        },
+        {
+          name: 'allow_list_remove',
+          label: this.$pgettext('Content/Moderation/Action/Verb', 'Remove from allow-list'),
+          filterCheckable: (obj) => {
+            return obj.allowed
+          }
+        },
       ]
     }
   },
@@ -179,6 +211,9 @@ export default {
     page () {
       this.fetchData()
     },
+    allowed () {
+      this.fetchData()
+    },
     ordering () {
       this.fetchData()
     },
diff --git a/front/src/views/admin/Settings.vue b/front/src/views/admin/Settings.vue
index 7102fb311b1b64fa9c63f160d026659ebe06a087..a1d03aab77740435d4636315196ad979482ea295 100644
--- a/front/src/views/admin/Settings.vue
+++ b/front/src/views/admin/Settings.vue
@@ -82,6 +82,7 @@ export default {
       let musicLabel = this.$pgettext('*/*/*/Noun', 'Music')
       let playlistsLabel = this.$pgettext('*/*/*', 'Playlists')
       let federationLabel = this.$pgettext('Content/Admin/Menu', 'Federation')
+      let moderationLabel = this.$pgettext('Content/Admin/Menu', 'Moderation')
       let subsonicLabel = this.$pgettext('Content/Admin/Menu', 'Subsonic')
       let statisticsLabel = this.$pgettext('Content/Admin/Menu', 'Statistics')
       let errorLabel = this.$pgettext('Content/Admin/Menu', 'Error reporting')
@@ -118,6 +119,14 @@ export default {
           id: "playlists",
           settings: ["playlists__max_tracks"]
         },
+        {
+          label: moderationLabel,
+          id: "moderation",
+          settings: [
+            "moderation__allow_list_enabled",
+            "moderation__allow_list_public",
+          ]
+        },
         {
           label: federationLabel,
           id: "federation",
diff --git a/front/src/views/admin/moderation/Base.vue b/front/src/views/admin/moderation/Base.vue
index 564debf79ae8f7dcc42abe94e073511de237f1ac..d1c3ae29fb8e7fb1a074f2dc65e0b30679e1c5f5 100644
--- a/front/src/views/admin/moderation/Base.vue
+++ b/front/src/views/admin/moderation/Base.vue
@@ -9,12 +9,31 @@
         :to="{name: 'manage.moderation.accounts.list'}"><translate translate-context="*/Moderation/Title">Accounts</translate></router-link>
 
     </nav>
-    <router-view :key="$route.fullPath"></router-view>
+    <router-view :allow-list-enabled="allowListEnabled" :key="$route.fullPath"></router-view>
   </div>
 </template>
 
 <script>
+import _ from '@/lodash'
+import axios from 'axios'
+
 export default {
+  data () {
+    return {
+      allowListEnabled: false
+    }
+  },
+  created () {
+    this.fetchNodeInfo()
+  },
+  methods: {
+    fetchNodeInfo () {
+      let self = this
+      axios.get('instance/nodeinfo/2.0/').then(response => {
+        self.allowListEnabled = _.get(response.data, 'metadata.allowList.enabled', false)
+      })
+    },
+  },
   computed: {
     labels() {
       return {
@@ -22,6 +41,6 @@ export default {
         secondaryMenu: this.$pgettext('Menu/*/Hidden text', "Secondary menu")
       }
     }
-  }
+  },
 }
 </script>
diff --git a/front/src/views/admin/moderation/DomainsDetail.vue b/front/src/views/admin/moderation/DomainsDetail.vue
index 575b15f93ca2bbf696b9672cbb38e7535c8b09ab..c30f426bbbca56045d292cffcc92d4784b457328 100644
--- a/front/src/views/admin/moderation/DomainsDetail.vue
+++ b/front/src/views/admin/moderation/DomainsDetail.vue
@@ -20,6 +20,34 @@
                   </div>
                 </div>
               </h2>
+              <div class="header-buttons">
+                <div class="ui icon buttons">
+                  <a
+                    v-if="$store.state.auth.profile.is_superuser"
+                    class="ui labeled icon button"
+                    :href="$store.getters['instance/absoluteUrl'](`/api/admin/federation/domain/${object.name}`)"
+                    target="_blank" rel="noopener noreferrer">
+                    <i class="wrench icon"></i>
+                    <translate translate-context="Content/Moderation/Link/Verb">View in Django's admin</translate>&nbsp;
+                  </a>
+                </div>
+                <div v-if="allowListEnabled" class="ui icon buttons">
+                  <button
+                    v-if="object.allowed"
+                    @click.prevent="setAllowList(false)"
+                    :class="['ui', 'labeled', {loading: isLoadingAllowList}, 'icon', 'button']">
+                    <i class="x icon"></i>
+                    <translate translate-context="Content/Moderation/Link/Verb">Remove from allow-list</translate>
+                  </button>
+                  <button
+                    v-else
+                    @click.prevent="setAllowList(true)"
+                    :class="['ui', 'labeled', {loading: isLoadingAllowList}, 'icon', 'button']">
+                    <i class="check icon"></i>
+                    <translate translate-context="Content/Moderation/Link/Verb">Add to allow-list</translate>
+                  </button>
+                </div>
+              </div>
             </div>
           </div>
           <div class="ui column">
@@ -74,6 +102,15 @@
               </h3>
               <table class="ui very basic table">
                 <tbody>
+                  <tr v-if="allowListEnabled">
+                    <td>
+                      <translate translate-context="Content/Moderation/*/Adjective">Is present on allow-list</translate>
+                    </td>
+                    <td>
+                      <translate v-if="object.allowed" translate-context="*/*/*">Yes</translate>
+                      <translate v-else translate-context="*/*/*">No</translate>
+                    </td>
+                  </tr>
                   <tr>
                     <td>
                       <translate translate-context="Content/*/Table.Label">Last checked</translate>
@@ -300,7 +337,7 @@ import InstancePolicyForm from "@/components/manage/moderation/InstancePolicyFor
 import InstancePolicyCard from "@/components/manage/moderation/InstancePolicyCard"
 
 export default {
-  props: ["id"],
+  props: ["id", "allowListEnabled"],
   components: {
     InstancePolicyForm,
     InstancePolicyCard,
@@ -311,6 +348,7 @@ export default {
       isLoading: true,
       isLoadingStats: false,
       isLoadingPolicy: false,
+      isLoadingAllowList: false,
       policy: null,
       object: null,
       stats: null,
@@ -353,6 +391,15 @@ export default {
         self.isLoadingPolicy = false
       })
     },
+    setAllowList(value) {
+      var self = this
+      this.isLoadingAllowList = true
+      let url = `manage/federation/domains/${this.id}/`
+      axios.patch(url, {allowed: value}).then(response => {
+        self.object = response.data
+        self.isLoadingAllowList = false
+      })
+    },
     refreshNodeInfo (data) {
       this.object.nodeinfo = data
       this.object.nodeinfo_fetch_date = new Date()
diff --git a/front/src/views/admin/moderation/DomainsList.vue b/front/src/views/admin/moderation/DomainsList.vue
index 3ce8e6afc44a2e653bc5ecb88a6837c3d80181d9..b4ffad7b8ca8b7e4b3d121e83474c806d6d4d0aa 100644
--- a/front/src/views/admin/moderation/DomainsList.vue
+++ b/front/src/views/admin/moderation/DomainsList.vue
@@ -14,6 +14,10 @@
             <label for="domain"><translate translate-context="Content/Moderation/Form.Label/Verb">Add a domain</translate></label>
             <input type="text" name="domain" id="domain" v-model="domainName">
           </div>
+          <div class="field" v-if="allowListEnabled">
+            <input type="checkbox" name="allowed" id="allowed" v-model="domainAllowed">
+            <label for="allowed"><translate translate-context="Content/Moderation/Form.Label/Verb">Add to allow-list</translate></label>
+          </div>
           <div class="field">
             <button :class="['ui', {'loading': isCreating}, 'green', 'button']" type="submit" :disabled="isCreating">
               <label for="domain"><translate translate-context="Content/Moderation/Button/Verb">Add</translate></label>
@@ -22,7 +26,7 @@
         </div>
       </form>
       <div class="ui clearing hidden divider"></div>
-      <domains-table></domains-table>
+      <domains-table :allow-list-enabled="allowListEnabled"></domains-table>
     </section>
   </main>
 </template>
@@ -32,12 +36,14 @@ import axios from 'axios'
 
 import DomainsTable from "@/components/manage/moderation/DomainsTable"
 export default {
+  props: ['allowListEnabled'],
   components: {
     DomainsTable
   },
   data () {
     return {
       domainName: '',
+      domainAllowed: this.allowListEnabled ? true : null,
       isCreating: false,
       errors: []
     }
@@ -54,7 +60,7 @@ export default {
       let self = this
       this.isCreating = true
       this.errors = []
-      axios.post('manage/federation/domains/', {name: this.domainName}).then((response) => {
+      axios.post('manage/federation/domains/', {name: this.domainName, allowed: this.domainAllowed}).then((response) => {
         this.isCreating = false
         this.$router.push({
           name: "manage.moderation.domains.detail",