diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index 5c0f6c63aa59d71786c1d991566f7ba185125a09..d69094916019b9655782f571a5b4ad760eddf82c 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -539,6 +539,70 @@ bool conf_val_equal(
 	return false;
 }
 
+conf_mix_iter_t conf_mix_iter(
+	conf_t *conf,
+	conf_val_t *mix_id)
+{
+	assert(mix_id != NULL && mix_id->item != NULL);
+	assert(mix_id->item->type == YP_TREF &&
+	       mix_id->item->var.r.ref != NULL &&
+	       mix_id->item->var.r.grp_ref != NULL &&
+	       mix_id->item->var.r.ref->var.g.id->type == YP_TSTR &&
+	       mix_id->item->var.r.grp_ref->var.g.id->type == YP_TSTR);
+
+	conf_mix_iter_t iter = {
+		.conf = conf,
+		.mix_id = mix_id,
+		.id = mix_id
+	};
+
+	if (mix_id->code != KNOT_EOK) {
+		return iter;
+	}
+
+	iter.sub_id = conf_id_get_txn(conf, &conf->read_txn,
+	                              mix_id->item->var.r.grp_ref_name,
+	                              mix_id->item->var.r.ref_name,
+	                              mix_id);
+	if (iter.sub_id.code == KNOT_EOK) {
+		conf_val(&iter.sub_id);
+		iter.id = &iter.sub_id;
+		iter.nested = true;
+	}
+
+	return iter;
+}
+
+void conf_mix_iter_next(
+	conf_mix_iter_t *iter)
+{
+	conf_val_next(iter->id);
+	if (iter->nested) {
+		if (iter->id->code == KNOT_EOK) {
+			return;
+		}
+		conf_val_next(iter->mix_id);
+		if (iter->mix_id->code != KNOT_EOK) {
+			return;
+		}
+	} else if (iter->id->code != KNOT_EOK){
+		return;
+	}
+
+	iter->sub_id = conf_id_get_txn(iter->conf, &iter->conf->read_txn,
+	                               iter->mix_id->item->var.r.grp_ref_name,
+	                               iter->mix_id->item->var.r.ref_name,
+	                               iter->mix_id);
+	if (iter->sub_id.code == KNOT_EOK) {
+		conf_val(&iter->sub_id);
+		iter->id = &iter->sub_id;
+		iter->nested = true;
+	} else {
+		iter->id = iter->mix_id;
+		iter->nested = false;
+	}
+}
+
 int64_t conf_int(
 	conf_val_t *val)
 {
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index d85c159fed24f0088b67d2f600e0933bf0dd5f7d..e45b3ec73310a9bf1161ff82478415f21fd59397 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -48,6 +48,20 @@ typedef struct {
 	int code;
 } conf_iter_t;
 
+/*! Configuration iterator over mixed references (e.g. remote and remotes). */
+typedef struct {
+	/*! Configuration context. */
+	conf_t *conf;
+	/*! Mixed references. */
+	conf_val_t *mix_id;
+	/*! Temporary nested references. */
+	conf_val_t sub_id;
+	/*! Current (possibly expanded) reference to use. */
+	conf_val_t *id;
+	/*! Nested references in use indication. */
+	bool nested;
+} conf_mix_iter_t;
+
 /*! Configuration module getter output. */
 typedef struct {
 	/*! Module name. */
@@ -407,6 +421,30 @@ bool conf_val_equal(
 	conf_val_t *val2
 );
 
+/*!
+ * Prepares a mixed reference iterator.
+ *
+ * The following access is through val->id.
+ *
+ * \param[in] conf    Configuration.
+ * \param[in] mix_id  First mixed reference.
+ *
+ * \return Mixed reference iterator.
+ */
+conf_mix_iter_t conf_mix_iter(
+	conf_t *conf,
+	conf_val_t *mix_id
+);
+
+/*!
+ * Increments the mixed iterator.
+ *
+ * \param[in] iter  Mixed reference iterator.
+ */
+void conf_mix_iter_next(
+	conf_mix_iter_t *iter
+);
+
 /*!
  * Gets the numeric value of the item.
  *
diff --git a/src/knot/conf/tools.c b/src/knot/conf/tools.c
index 74e2841da7470243c9618b6d9b9c86617f0951de..f7cbfc28014a263300387ee7d626858d336949cf 100644
--- a/src/knot/conf/tools.c
+++ b/src/knot/conf/tools.c
@@ -212,12 +212,27 @@ int check_ref(
 	knotd_conf_check_args_t *args)
 {
 	const yp_item_t *ref = args->item->var.r.ref;
+	const yp_item_t *ref2 = args->item->var.r.grp_ref;
 
-	// Try to find a referenced block with the id.
-	if (!conf_rawid_exists_txn(args->extra->conf, args->extra->txn, ref->name,
-	                           args->data, args->data_len)) {
-		args->err_str = "invalid reference";
-		return KNOT_ENOENT;
+	bool found1 = false, found2 = false;
+
+	// Try to find the id in the first section.
+	found1 = conf_rawid_exists_txn(args->extra->conf, args->extra->txn,
+	                               ref->name, args->data, args->data_len);
+	if (ref2 != NULL) {
+		// Try to find the id in the second section if supported.
+		found2 = conf_rawid_exists_txn(args->extra->conf, args->extra->txn,
+		                               ref2->name, args->data, args->data_len);
+	}
+
+	if (found1 == found2) {
+		if (found1) {
+			args->err_str = "ambiguous reference";
+			return KNOT_ENOENT;
+		} else {
+			args->err_str = "invalid reference";
+			return KNOT_ENOENT;
+		}
 	}
 
 	return KNOT_EOK;
diff --git a/src/libknot/yparser/ypschema.c b/src/libknot/yparser/ypschema.c
index 0da1ff12b296172001bd77beeed0d7aa4d486b46..0ac5b571e8bce73fd91237a46b239def139e76a9 100644
--- a/src/libknot/yparser/ypschema.c
+++ b/src/libknot/yparser/ypschema.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -43,15 +43,24 @@ static int set_ref_item(
 		return KNOT_EINVAL;
 	}
 
-	// Get reference category.
+	// Get referenced section.
 	const yp_name_t *ref_name = dst->var.r.ref_name;
 	const yp_item_t *ref = yp_schema_find(ref_name, NULL, schema);
 	if (ref == NULL) {
 		return KNOT_YP_EINVAL_ITEM;
 	}
-
 	dst->var.r.ref = ref;
 
+	// Get referenced group if supported.
+	const yp_name_t *grp_ref_name = dst->var.r.grp_ref_name;
+	if (grp_ref_name != NULL) {
+		const yp_item_t *grp_ref = yp_schema_find(grp_ref_name, NULL, schema);
+		if (grp_ref == NULL) {
+			return KNOT_YP_EINVAL_ITEM;
+		}
+		dst->var.r.grp_ref = grp_ref;
+	}
+
 	return KNOT_EOK;
 }
 
diff --git a/src/libknot/yparser/ypschema.h b/src/libknot/yparser/ypschema.h
index bb3e425af0aa90e2ae8925c3d1abdd18428bd225..91e516574785be955c2fdfb5dda39ba72d484591 100644
--- a/src/libknot/yparser/ypschema.h
+++ b/src/libknot/yparser/ypschema.h
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -168,10 +168,14 @@ typedef union {
 	} d;
 	/*! Reference variables. */
 	struct {
-		/*! Referenced group name. */
+		/*! Referenced section name. */
 		yp_name_t const *ref_name;
-		/*! Referenced item (dynamic value). */
+		/*! Referenced group section name (optional). */
+		yp_name_t const *grp_ref_name;
+		/*! Referenced section item (dynamic value). */
 		yp_item_t const *ref;
+		/*! Referenced group section item (dynamic value). */
+		yp_item_t const *grp_ref;
 	} r;
 	/*! Group variables. */
 	struct {