diff --git a/api/v1alpha1/drupalprojectconfig_types.go b/api/v1alpha1/drupalprojectconfig_types.go
index db4cc702964b7dc37d6c20f9761840315186497b..17042fadc15e1cbc920233f7668c4f199a5be21c 100644
--- a/api/v1alpha1/drupalprojectconfig_types.go
+++ b/api/v1alpha1/drupalprojectconfig_types.go
@@ -25,6 +25,9 @@ type DrupalProjectConfigSpec struct {
 	// PrimarySiteName defines the primary DrupalSite instance of a project
 	// +optional
 	PrimarySiteName string `json:"primarySiteName,omitempty"`
+	// PrimarySiteUrl defines the primary urls of a project
+	// +optional
+	PrimarySiteUrl []Url `json:"primarySiteUrl,omitempty"`
 }
 
 // DrupalProjectConfigStatus defines the observed state of DrupalProjectConfig
diff --git a/api/v1alpha1/drupalsite_types.go b/api/v1alpha1/drupalsite_types.go
index 9eb69e8be9493c432cd1555364a9983ed63058a0..66f79af511dc8481d4a5a0b0b3b4050f68faa4ea 100644
--- a/api/v1alpha1/drupalsite_types.go
+++ b/api/v1alpha1/drupalsite_types.go
@@ -159,6 +159,10 @@ type DrupalSiteStatus struct {
 	// IsPrimary states if the Drupalsite is the main instance of the project
 	// +kubebuilder:default=false
 	IsPrimary bool `json:"isPrimary,omitempty"`
+
+	// SiteUrl defines the urls of a site
+	// +optional
+	SiteUrl []Url `json:"siteUrl,omitempty"`
 }
 
 // ReleaseID reports the actual release of CERN Drupal Distribution that is being used in the deployment.
diff --git a/config/crd/bases/drupal.webservices.cern.ch_drupalprojectconfigs.yaml b/config/crd/bases/drupal.webservices.cern.ch_drupalprojectconfigs.yaml
index 069919d86631d3dd423c2cec9a07954a05ce4c21..a2620ea6066a8e19ed2ab1cb2757f070f161797b 100644
--- a/config/crd/bases/drupal.webservices.cern.ch_drupalprojectconfigs.yaml
+++ b/config/crd/bases/drupal.webservices.cern.ch_drupalprojectconfigs.yaml
@@ -41,6 +41,13 @@ spec:
                 description: PrimarySiteName defines the primary DrupalSite instance
                   of a project
                 type: string
+              primarySiteUrl:
+                description: PrimarySiteUrl defines the primary urls of a project
+                items:
+                  description: Url refers to where the site should be made available.
+                  pattern: '[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)'
+                  type: string
+                type: array
             type: object
           status:
             description: DrupalProjectConfigStatus defines the observed state of DrupalProjectConfig
diff --git a/config/crd/bases/drupal.webservices.cern.ch_drupalsiteconfigoverrides.yaml b/config/crd/bases/drupal.webservices.cern.ch_drupalsiteconfigoverrides.yaml
index 977bde900048b41294eea05c07f882abb61ca869..e31c649be91c09c80e25a87dba5ac555eadbce45 100644
--- a/config/crd/bases/drupal.webservices.cern.ch_drupalsiteconfigoverrides.yaml
+++ b/config/crd/bases/drupal.webservices.cern.ch_drupalsiteconfigoverrides.yaml
@@ -54,7 +54,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -66,7 +66,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
@@ -86,7 +86,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -98,7 +98,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
@@ -118,7 +118,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -130,7 +130,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
@@ -150,7 +150,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -162,7 +162,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
@@ -182,7 +182,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -194,7 +194,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
@@ -214,7 +214,7 @@ spec:
                           pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                           x-kubernetes-int-or-string: true
                         description: 'Limits describes the maximum amount of compute
-                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                       requests:
                         additionalProperties:
@@ -226,7 +226,7 @@ spec:
                         description: 'Requests describes the minimum amount of compute
                           resources required. If Requests is omitted for a container,
                           it defaults to Limits if that is explicitly specified, otherwise
-                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                          to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                         type: object
                     type: object
                 type: object
diff --git a/config/crd/bases/drupal.webservices.cern.ch_drupalsites.yaml b/config/crd/bases/drupal.webservices.cern.ch_drupalsites.yaml
index 3d2aed9bc383bbb7f481e2acb2c7869e302d19fa..9c6741ebe9fa32f6b05f7cd6f9acad48d8c1c8f8 100644
--- a/config/crd/bases/drupal.webservices.cern.ch_drupalsites.yaml
+++ b/config/crd/bases/drupal.webservices.cern.ch_drupalsites.yaml
@@ -238,6 +238,13 @@ spec:
                 description: ServingPodImage reports the complete image name of the
                   PHP-FPM container that is being used in the deployment.
                 type: string
+              siteUrl:
+                description: SiteUrl defines the urls of a site
+                items:
+                  description: Url refers to where the site should be made available.
+                  pattern: '[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)'
+                  type: string
+                type: array
             type: object
         required:
         - spec
diff --git a/controllers/drupalsite_controller.go b/controllers/drupalsite_controller.go
index fd4e60e1766373c5acb996a67871cfa9381c928b..b3bdd50ac5bbf4fb1cb300a1727c51d81fbbebd9 100644
--- a/controllers/drupalsite_controller.go
+++ b/controllers/drupalsite_controller.go
@@ -437,7 +437,7 @@ func (r *DrupalSiteReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	}
 
 	// Ensure all resources (server deployment is excluded here during updates)
-	if transientErrs := r.ensureResources(drupalSite, deploymentConfig, log); transientErrs != nil {
+	if transientErrs := r.ensureResources(drupalSite, drupalProjectConfig, deploymentConfig, log); transientErrs != nil {
 		transientErr := concat(transientErrs)
 		return handleTransientErr(transientErr, "%v while ensuring the resources", "Ready")
 	}
@@ -453,6 +453,15 @@ func (r *DrupalSiteReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 
 	log.V(3).Info("Ensured all resources are present.")
 
+	// Update status of drupalsite with primary urls
+	if drupalSite.Status.IsPrimary && !routesEqual(drupalSite.Status.SiteUrl, uniqueRoutes(drupalSite.Spec.SiteURL, drupalProjectConfig.Spec.PrimarySiteUrl)) {
+		drupalSite.Status.SiteUrl = uniqueRoutes(drupalSite.Spec.SiteURL, drupalProjectConfig.Spec.PrimarySiteUrl)
+		return r.updateCRStatusOrFailReconcile(ctx, log, drupalSite)
+	} else if !drupalSite.Status.IsPrimary {
+		drupalSite.Status.SiteUrl = drupalSite.Spec.SiteURL
+		return r.updateCRStatusOrFailReconcile(ctx, log, drupalSite)
+	}
+
 	// 4. Check DBOD has been provisioned and reconcile if needed
 
 	if dbodReady := r.isDBODProvisioned(ctx, drupalSite); !dbodReady {
diff --git a/controllers/drupalsite_controller_test.go b/controllers/drupalsite_controller_test.go
index c204857f2bbe3422107e578d25cff797f0890641..7f05895dddd9cea1289974b58b40331616d1abd3 100644
--- a/controllers/drupalsite_controller_test.go
+++ b/controllers/drupalsite_controller_test.go
@@ -20,6 +20,7 @@ import (
 	"context"
 	"crypto/md5"
 	"encoding/hex"
+	"reflect"
 	"time"
 
 	. "github.com/onsi/ginkgo"
@@ -60,7 +61,9 @@ var _ = Describe("DrupalSite controller", func() {
 		interval        = time.Millisecond * 250
 	)
 	var (
-		drupalSiteObject = &drupalwebservicesv1alpha1.DrupalSite{}
+		drupalSiteObject    = &drupalwebservicesv1alpha1.DrupalSite{}
+		drupalSiteObjectDev = &drupalwebservicesv1alpha1.DrupalSite{}
+		drupalProjectConfig = &drupalwebservicesv1alpha1.DrupalProjectConfig{}
 	)
 
 	ctx := context.Background()
@@ -96,6 +99,22 @@ var _ = Describe("DrupalSite controller", func() {
 				},
 			},
 		}
+		drupalProjectConfig = &drupalwebservicesv1alpha1.DrupalProjectConfig{
+			TypeMeta: metav1.TypeMeta{
+				APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+				Kind:       "DrupalSite",
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      key.Name,
+				Namespace: key.Namespace,
+			},
+			Spec: drupalwebservicesv1alpha1.DrupalProjectConfigSpec{
+				PrimarySiteName: key.Name,
+				PrimarySiteUrl: []drupalwebservicesv1alpha1.Url{
+					"test-primary.webtest.cern.ch",
+				},
+			},
+		}
 	})
 
 	Describe("Creating drupalSite object", func() {
@@ -119,6 +138,11 @@ var _ = Describe("DrupalSite controller", func() {
 					return k8sClient.Create(ctx, drupalSiteObject)
 				}, timeout, interval).Should(Succeed())
 
+				By("By creating a drupalProjectConfig")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalProjectConfig)
+				}, timeout, interval).Should(Succeed())
+
 				By("Expecting drupalSite object created")
 				cr := drupalwebservicesv1alpha1.DrupalSite{}
 				Eventually(func() error {
@@ -766,6 +790,22 @@ var _ = Describe("DrupalSite controller", func() {
 						SiteURL: []drupalwebservicesv1alpha1.Url{dummySiteUrl},
 					},
 				}
+				drupalProjectConfig = &drupalwebservicesv1alpha1.DrupalProjectConfig{
+					TypeMeta: metav1.TypeMeta{
+						APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+						Kind:       "DrupalSite",
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      key.Name,
+						Namespace: key.Namespace,
+					},
+					Spec: drupalwebservicesv1alpha1.DrupalProjectConfigSpec{
+						PrimarySiteName: key.Name,
+						PrimarySiteUrl: []drupalwebservicesv1alpha1.Url{
+							"test-primary.webtest.cern.ch",
+						},
+					},
+				}
 
 				By("By creating the testing namespace")
 				Eventually(func() error {
@@ -779,6 +819,11 @@ var _ = Describe("DrupalSite controller", func() {
 					return k8sClient.Create(ctx, drupalSiteObject)
 				}, timeout, interval).Should(Succeed())
 
+				By("By creating a drupalProjectConfig")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalProjectConfig)
+				}, timeout, interval).Should(Succeed())
+
 				// Create drupalSite object
 				By("Expecting drupalSite object created")
 				cr := drupalwebservicesv1alpha1.DrupalSite{}
@@ -1496,6 +1541,22 @@ var _ = Describe("DrupalSite controller", func() {
 						SiteURL: []drupalwebservicesv1alpha1.Url{dummySiteUrl},
 					},
 				}
+				drupalProjectConfig = &drupalwebservicesv1alpha1.DrupalProjectConfig{
+					TypeMeta: metav1.TypeMeta{
+						APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+						Kind:       "DrupalSite",
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      key.Name,
+						Namespace: key.Namespace,
+					},
+					Spec: drupalwebservicesv1alpha1.DrupalProjectConfigSpec{
+						PrimarySiteName: key.Name,
+						PrimarySiteUrl: []drupalwebservicesv1alpha1.Url{
+							"test-primary.webtest.cern.ch",
+						},
+					},
+				}
 
 				By("By creating the testing namespace")
 				Eventually(func() error {
@@ -1504,6 +1565,11 @@ var _ = Describe("DrupalSite controller", func() {
 					})
 				}, timeout, interval).Should(Succeed())
 
+				By("By creating a drupalProjectConfig")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalProjectConfig)
+				}, timeout, interval).Should(Succeed())
+
 				By("By creating a new drupalSite")
 				Eventually(func() error {
 					return k8sClient.Create(ctx, drupalSiteObject)
@@ -1981,6 +2047,136 @@ var _ = Describe("DrupalSite controller", func() {
 			})
 		})
 	})
+	Describe("Using DrupalProjectConfig", func() {
+		Context("Promoting a drupalsite to primary", func() {
+			It("Should update the status.siteUrl of each site", func() {
+				key = types.NamespacedName{
+					Name:      Name + "-primary",
+					Namespace: "drupalprojectconfig",
+				}
+				drupalSiteObject = &drupalwebservicesv1alpha1.DrupalSite{
+					TypeMeta: metav1.TypeMeta{
+						APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+						Kind:       "DrupalSite",
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      key.Name,
+						Namespace: key.Namespace,
+					},
+					Spec: drupalwebservicesv1alpha1.DrupalSiteSpec{
+						Version: drupalwebservicesv1alpha1.Version{
+							Name:        "v8.9-1",
+							ReleaseSpec: "stable",
+						},
+						Configuration: drupalwebservicesv1alpha1.Configuration{
+							DiskSize:      "10Gi",
+							QoSClass:      drupalwebservicesv1alpha1.QoSStandard,
+							DatabaseClass: drupalwebservicesv1alpha1.DBODStandard,
+						},
+						SiteURL: []drupalwebservicesv1alpha1.Url{dummySiteUrl},
+					},
+				}
+				drupalSiteObjectDev = &drupalwebservicesv1alpha1.DrupalSite{
+					TypeMeta: metav1.TypeMeta{
+						APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+						Kind:       "DrupalSite",
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      key.Name + "dev",
+						Namespace: key.Namespace,
+					},
+					Spec: drupalwebservicesv1alpha1.DrupalSiteSpec{
+						Version: drupalwebservicesv1alpha1.Version{
+							Name:        "v8.9-1",
+							ReleaseSpec: "stable",
+						},
+						Configuration: drupalwebservicesv1alpha1.Configuration{
+							DiskSize:      "10Gi",
+							QoSClass:      drupalwebservicesv1alpha1.QoSStandard,
+							DatabaseClass: drupalwebservicesv1alpha1.DBODStandard,
+						},
+						SiteURL: []drupalwebservicesv1alpha1.Url{"test-dev.webtest.cern.ch"},
+					},
+				}
+				drupalProjectConfig = &drupalwebservicesv1alpha1.DrupalProjectConfig{
+					TypeMeta: metav1.TypeMeta{
+						APIVersion: "drupal.webservices.cern.ch/v1alpha1",
+						Kind:       "DrupalSite",
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      key.Name,
+						Namespace: key.Namespace,
+					},
+					Spec: drupalwebservicesv1alpha1.DrupalProjectConfigSpec{
+						PrimarySiteName: key.Name,
+						PrimarySiteUrl: []drupalwebservicesv1alpha1.Url{
+							"test-primary.webtest.cern.ch",
+						},
+					},
+				}
+
+				By("By creating the testing namespace")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
+						Name: key.Namespace},
+					})
+				}, timeout, interval).Should(Succeed())
+
+				By("By creating a drupalProjectConfig")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalProjectConfig)
+				}, timeout, interval).Should(Succeed())
+
+				By("By creating a new drupalSite")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalSiteObject)
+				}, timeout, interval).Should(Succeed())
+
+				By("Expecting the isPrimary status field in drupalSite")
+				Eventually(func() bool {
+					cr := drupalwebservicesv1alpha1.DrupalSite{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name, Namespace: key.Namespace}, &cr)
+					return cr.Status.IsPrimary == true
+				}, timeout, interval).Should(BeTrue())
+
+				By("Expecting the siteUrl status field in drupalSite")
+				Eventually(func() bool {
+					cr := drupalwebservicesv1alpha1.DrupalSite{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name, Namespace: key.Namespace}, &cr)
+					return reflect.DeepEqual(cr.Status.SiteUrl, []drupalwebservicesv1alpha1.Url{dummySiteUrl, "test-primary.webtest.cern.ch"})
+				}, timeout, interval).Should(BeTrue())
+
+				By("Expecting the primarySiteName spec field in drupalSiteProjectConfig")
+				Eventually(func() bool {
+					dpc := drupalwebservicesv1alpha1.DrupalProjectConfig{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name, Namespace: key.Namespace}, &dpc)
+					return dpc.Spec.PrimarySiteName == key.Name
+				}, timeout, interval).Should(BeTrue())
+
+				By("By creating a second drupalSite")
+				Eventually(func() error {
+					return k8sClient.Create(ctx, drupalSiteObjectDev)
+				}, timeout, interval).Should(Succeed())
+
+				By("Changing the primary site")
+				Eventually(func() error {
+					dpc := drupalwebservicesv1alpha1.DrupalProjectConfig{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name, Namespace: key.Namespace}, &dpc)
+					dpc.Spec.PrimarySiteName = key.Name + "dev"
+					return k8sClient.Update(ctx, &dpc)
+				}, timeout, interval).Should(Succeed())
+
+				By("Expecting the siteUrl status field to be uddated in both drupalSites")
+				Eventually(func() bool {
+					cr_old_primary := drupalwebservicesv1alpha1.DrupalSite{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name, Namespace: key.Namespace}, &cr_old_primary)
+					cr_new_primary := drupalwebservicesv1alpha1.DrupalSite{}
+					k8sClient.Get(ctx, types.NamespacedName{Name: key.Name + "dev", Namespace: key.Namespace}, &cr_new_primary)
+					return reflect.DeepEqual(cr_old_primary.Status.SiteUrl, []drupalwebservicesv1alpha1.Url{dummySiteUrl}) && reflect.DeepEqual(cr_new_primary.Status.SiteUrl, []drupalwebservicesv1alpha1.Url{"test-dev.webtest.cern.ch", "test-primary.webtest.cern.ch"})
+				}, timeout, interval).Should(BeTrue())
+			})
+		})
+	})
 	Describe("Deleting the drupalsite object", func() {
 		Context("With critical QoS", func() {
 			It("Should be deleted successfully", func() {
diff --git a/controllers/drupalsite_resources.go b/controllers/drupalsite_resources.go
index 9c9c5fa8286d553646ca7817a82df37ed0bcf590..36db838d2896e0c499330d719b91156b5d426eba 100644
--- a/controllers/drupalsite_resources.go
+++ b/controllers/drupalsite_resources.go
@@ -196,46 +196,46 @@ func (r *DrupalSiteReconciler) ensureDeploymentConfigmapHash(ctx context.Context
 ensureResources ensures the presence of all the resources that the DrupalSite needs to serve content.
 This includes BuildConfigs/ImageStreams, DB, PVC, PHP/Nginx deployment + service, site install job, Routes.
 */
-func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite, deploymentConfig DeploymentConfig, log logr.Logger) (transientErrs []reconcileError) {
+func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite, dpc *webservicesv1a1.DrupalProjectConfig, deploymentConfig DeploymentConfig, log logr.Logger) (transientErrs []reconcileError) {
 	ctx := context.TODO()
 
 	// 1. BuildConfigs and ImageStreams
 
 	if len(drp.Spec.Configuration.ExtraConfigurationRepo) > 0 {
-		if transientErr := r.ensureResourceX(ctx, drp, "is_s2i", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "is_s2i", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for S2I SiteBuilder ImageStream"))
 		}
-		if transientErr := r.ensureResourceX(ctx, drp, "bc_s2i", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "bc_s2i", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for S2I SiteBuilder BuildConfig"))
 		}
-		if transientErr := r.ensureResourceX(ctx, drp, "gitlab_trigger_secret", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "gitlab_trigger_secret", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for S2I SiteBuilder Secret"))
 		}
 	}
 	// 2. Data layer
 
-	if transientErr := r.ensureResourceX(ctx, drp, "pvc_drupal", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "pvc_drupal", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for Drupal PVC"))
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "dbod_cr", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "dbod_cr", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for DBOD resource"))
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "webdav_secret", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "webdav_secret", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for WebDAV Secret"))
 	}
 
 	// 3. Serving layer
 
-	if transientErr := r.ensureResourceX(ctx, drp, "cm_php", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "cm_php", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for PHP-FPM CM"))
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "cm_nginx_global", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "cm_nginx_global", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for Nginx CM"))
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "cm_settings", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "cm_settings", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for settings.php CM"))
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "cm_php_cli", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "cm_php_cli", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for PHP Job CM"))
 	}
 	if r.isDBODProvisioned(ctx, drp) {
@@ -243,7 +243,7 @@ func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite,
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for Drupal deployment"))
 		}
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "svc_nginx", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "svc_nginx", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for Nginx SVC"))
 	}
 	/* A new drupalsite can be initialized with 3 different ways depending its Spec:
@@ -256,15 +256,15 @@ func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite,
 	if r.isDBODProvisioned(ctx, drp) && !(drp.ConditionTrue("Initialized")) {
 		switch {
 		case drp.Spec.Configuration.CloneFrom != "":
-			if transientErr := r.ensureResourceX(ctx, drp, "clone_job", log); transientErr != nil {
+			if transientErr := r.ensureResourceX(ctx, drp, dpc, "clone_job", log); transientErr != nil {
 				transientErrs = append(transientErrs, transientErr.Wrap("%v: for clone Job"))
 			}
 		case drp.Spec.Configuration.Easystart == "enable":
-			if transientErr := r.ensureResourceX(ctx, drp, "easystart_taskrun", log); transientErr != nil {
+			if transientErr := r.ensureResourceX(ctx, drp, dpc, "easystart_taskrun", log); transientErr != nil {
 				transientErrs = append(transientErrs, transientErr.Wrap("%v: for easystart TaskRun"))
 			}
 		default:
-			if transientErr := r.ensureResourceX(ctx, drp, "site_install_job", log); transientErr != nil {
+			if transientErr := r.ensureResourceX(ctx, drp, dpc, "site_install_job", log); transientErr != nil {
 				transientErrs = append(transientErrs, transientErr.Wrap("%v: for site install Job"))
 			}
 		}
@@ -274,15 +274,15 @@ func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite,
 
 	if drp.ConditionTrue("Initialized") {
 		// each function below ensures 1 route per entry in `spec.siteUrl[]`. This is understandably part of the job of "ensuring resource X".
-		if transientErr := r.ensureResourceX(ctx, drp, "route", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "route", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for Route"))
 		}
-		if transientErr := r.ensureResourceX(ctx, drp, "oidc_return_uri", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "oidc_return_uri", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for OidcReturnURI"))
 		}
 
 		// each function below removes any unwanted routes
-		if transientErr := r.ensureNoExtraRouteResource(ctx, drp, "drupal", log); transientErr != nil {
+		if transientErr := r.ensureNoExtraRouteResource(ctx, drp, dpc, "drupal", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: while ensuring no extra routes"))
 		}
 		if transientErr := r.ensureNoExtraOidcReturnUriResource(ctx, drp, "drupal", log); transientErr != nil {
@@ -302,7 +302,7 @@ func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite,
 	// 5. Cluster-scoped: Backup schedule, Tekton RBAC
 	// Create Velero schedule only after site is initialized in order for the first backup to not report 'Failed' or 'PartiallyFailed' status
 	if drp.ConditionTrue("Initialized") && (drp.Status.IsPrimary || drp.Spec.Configuration.ScheduledBackups == "enabled") {
-		if transientErr := r.ensureResourceX(ctx, drp, "backup_schedule", log); transientErr != nil {
+		if transientErr := r.ensureResourceX(ctx, drp, dpc, "backup_schedule", log); transientErr != nil {
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: for Velero Schedule"))
 		}
 	} else {
@@ -310,7 +310,7 @@ func (r *DrupalSiteReconciler) ensureResources(drp *webservicesv1a1.DrupalSite,
 			transientErrs = append(transientErrs, transientErr.Wrap("%v: while deleting the Velero schedule"))
 		}
 	}
-	if transientErr := r.ensureResourceX(ctx, drp, "tekton_extra_perm_rbac", log); transientErr != nil {
+	if transientErr := r.ensureResourceX(ctx, drp, dpc, "tekton_extra_perm_rbac", log); transientErr != nil {
 		transientErrs = append(transientErrs, transientErr.Wrap("%v: for Tekton Extra Permissions ClusterRoleBinding"))
 	}
 	return transientErrs
@@ -339,7 +339,7 @@ ensureResourceX ensure the requested resource is created, with the following val
 	- tekton_extra_perm_rbac: ClusterRoleBinding for tekton tasks
 	- gitlab_trigger_secret: Secret for Gitlab trigger config in buildconfig
 */
-func (r *DrupalSiteReconciler) ensureResourceX(ctx context.Context, d *webservicesv1a1.DrupalSite, resType string, log logr.Logger) (transientErr reconcileError) {
+func (r *DrupalSiteReconciler) ensureResourceX(ctx context.Context, d *webservicesv1a1.DrupalSite, dpc *webservicesv1a1.DrupalProjectConfig, resType string, log logr.Logger) (transientErr reconcileError) {
 	switch resType {
 	case "is_s2i":
 		is := &imagev1.ImageStream{ObjectMeta: metav1.ObjectMeta{Name: "sitebuilder-s2i-" + d.Name, Namespace: d.Namespace}}
@@ -398,6 +398,9 @@ func (r *DrupalSiteReconciler) ensureResourceX(ctx context.Context, d *webservic
 		return nil
 	case "route":
 		routeRequestList := d.Spec.SiteURL
+		if d.Status.IsPrimary {
+			routeRequestList = uniqueRoutes(routeRequestList, dpc.Spec.PrimarySiteUrl)
+		}
 		for _, req := range routeRequestList {
 			hash := md5.Sum([]byte(req))
 			route := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: d.Name + "-" + hex.EncodeToString(hash[0:4]), Namespace: d.Namespace}}
@@ -596,7 +599,7 @@ func (r *DrupalSiteReconciler) ensureDrupalDeployment(ctx context.Context, d *we
 }
 
 // ensureNoExtraRouteResource uses the current SiteURL resource as reference and deletes any extra route
-func (r *DrupalSiteReconciler) ensureNoExtraRouteResource(ctx context.Context, d *webservicesv1a1.DrupalSite, label string, log logr.Logger) (transientErr reconcileError) {
+func (r *DrupalSiteReconciler) ensureNoExtraRouteResource(ctx context.Context, d *webservicesv1a1.DrupalSite, dpc *webservicesv1a1.DrupalProjectConfig, label string, log logr.Logger) (transientErr reconcileError) {
 	ls := labelsForDrupalSite(d.Name)
 	ls["app"] = "drupal"
 	ls["route"] = label
@@ -618,6 +621,10 @@ func (r *DrupalSiteReconciler) ensureNoExtraRouteResource(ctx context.Context, d
 	}
 	routeRequestList := d.Spec.SiteURL
 	routesToRemove := []webservicesv1a1.Url{}
+	if d.Status.IsPrimary {
+		routeRequestList = uniqueRoutes(routeRequestList, dpc.Spec.PrimarySiteUrl)
+	}
+
 	for _, route := range existingRoutes.Items {
 		flag := false
 		for _, req := range routeRequestList {
@@ -2262,3 +2269,43 @@ func containerExists(name string, currentobject *appsv1.Deployment) {
 		currentobject.Spec.Template.Spec.Containers = append(currentobject.Spec.Template.Spec.Containers, corev1.Container{Name: name})
 	}
 }
+
+// uniqueRoutes returns the total routes of a drupalsite
+func uniqueRoutes(routeRequestList []webservicesv1a1.Url, primarySiteUrl []webservicesv1a1.Url) []webservicesv1a1.Url {
+	routeRequestList = append(routeRequestList, primarySiteUrl...)
+	keys := make(map[string]bool)
+	uniqueRouteRequestList := []webservicesv1a1.Url{}
+	for _, route := range routeRequestList {
+		if _, value := keys[string(route)]; !value {
+			keys[string(route)] = true
+			uniqueRouteRequestList = append(uniqueRouteRequestList, route)
+		}
+	}
+	return uniqueRouteRequestList
+}
+
+// routesEqual compares the urls of drupalsite.status.siteUrl with the total of
+// drupalsite.spec.siteUrl and drupalProjectConfig.spec.PrimaryUrl
+func routesEqual(currentRoutes []webservicesv1a1.Url, expectedRoutes []webservicesv1a1.Url) bool {
+	if len(currentRoutes) != len(expectedRoutes) {
+		return false
+	} else {
+		for _, currentRoute := range currentRoutes {
+			if !findUrl(expectedRoutes, string(currentRoute)) {
+				return false
+			}
+		}
+		return true
+	}
+
+}
+
+// Checks if a url exists in a Url slice
+func findUrl(urls []webservicesv1a1.Url, url string) bool {
+	for _, item := range urls {
+		if string(item) == url {
+			return true
+		}
+	}
+	return false
+}