diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..db8c388
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+.github
+.trunk
+.idea
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 72e9f94..47114e9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,6 +15,11 @@ concurrency:
   cancel-in-progress: true
 
 jobs:
+  tests:
+    name: "Tests"
+    uses: ./.github/workflows/tests.yml
+    permissions:
+      contents: read
   build-container:
     name: Build
     uses: ./.github/workflows/docker.build.yml
@@ -52,6 +57,7 @@ jobs:
       - validate-container
       - check-php
       - check-trunk
+      - tests
     uses: ./.github/workflows/docker.release.yml
     secrets: inherit
     permissions:
diff --git a/.github/workflows/docker.clean.yml b/.github/workflows/docker.clean.yml
index 9a5e19a..b58ddfa 100644
--- a/.github/workflows/docker.clean.yml
+++ b/.github/workflows/docker.clean.yml
@@ -12,31 +12,27 @@ on:
     types:
       - completed
 
-env:
-  CANDIDATE_IMAGE: ghcr.io/benzine-framework/bouncer
-  CANDIDATE_TAG: build-${{ github.sha }}
-
 jobs:
   cleanup-delete-candidate-image:
     name: Delete candidate image
     runs-on: ubuntu-latest
     steps:
       - run: docker login ghcr.io -u ${{ github.repository_owner }} -p ${{ secrets.GITHUB_TOKEN }}
-      - uses: dataaxiom/ghcr-cleanup-action@main
+      - uses: dataaxiom/ghcr-cleanup-action@v1.0.3
         with:
-          owner: ${{ github.repository_owner }}
-          repository: ${{ github.repository }}
-          name: ${{ env.CANDIDATE_IMAGE }}
-          tags: ${{ env.CANDIDATE_TAG }}
+          owner: benzine-framework
+          repository: docker-swarm-loadbalancer
+          name: bouncer
+          tags: build-${{ github.sha }}
           token: ${{ secrets.GITHUB_TOKEN }}
   cleanup-untagged-images:
     name: Delete untagged images
     runs-on: ubuntu-latest
     steps:
       - run: docker login ghcr.io -u ${{ github.repository_owner }} -p ${{ secrets.GITHUB_TOKEN }}
-      - uses: dataaxiom/ghcr-cleanup-action@main
+      - uses: dataaxiom/ghcr-cleanup-action@v1.0.3
         with:
-          owner: ${{ github.repository_owner }}
-          repository: ${{ github.repository }}
-          name: ${{ env.CANDIDATE_IMAGE }}
+          owner: benzine-framework
+          repository: docker-swarm-loadbalancer
+          name: bouncer
           token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..d29eccc
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,72 @@
+name: "Tests"
+
+permissions:
+  contents: read
+
+on:
+  workflow_call:
+  workflow_dispatch:
+
+jobs:
+  test-integration:
+    name: Integration Tests
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: Start Bouncer
+        run: docker compose up --build -d bouncer test-box
+
+      - name: Give it a moment...
+        run: sleep 5
+
+      - name: No-SSL Connect to Web A
+        run: |
+          docker compose exec test-box curl -s -D - http://a.example.org > a.nossl.http
+          grep "HTTP/1.1 200 OK" a.nossl.http;
+          grep "<h1>Website A</h1>" a.nossl.http;
+      - name: SSL Connect to Web A
+        run: |
+          docker compose exec test-box curl -s -k -D - https://a.example.org 2>&1 > a.ssl.http;
+          grep "HTTP/1.1 200 OK" a.ssl.http;
+          grep "<h1>Website A</h1>" a.ssl.http;
+
+      - name: No-SSL Connect to Web B
+        run: |
+          docker compose exec test-box curl -s -D - http://b.example.org 2>&1 > b.nossl.http 
+          grep "HTTP/1.1 200 OK" b.nossl.http
+          grep "<h1>Website B</h1>" b.nossl.http
+      - name: SSL Connect to Web B
+        run: |
+          docker compose exec test-box curl -s -k -D - https://b.example.org 2>&1 > b.ssl.http
+          grep "HTTP/1.1 200 OK" b.ssl.http
+          grep "<h1>Website B</h1>" b.ssl.http
+
+      - name: No-SSL Connect to SSL-redirect
+        run: |
+          docker compose exec test-box curl -s -D - http://redirect-to-ssl.example.org 2>&1 > redirect.nossl.http
+          # Validate its redirected
+          grep "HTTP/1.1 301 Moved Permanently" redirect.nossl.http
+          # And going to the right place
+          grep "Location: https://redirect-to-ssl.example.org" redirect.nossl.http
+      - name: SSL Connect to SSL-redirect
+        run: |
+          docker compose exec test-box curl -s -k -D - https://redirect-to-ssl.example.org 2>&1 > redirect.ssl.http
+          grep "HTTP/1.1 200 OK" redirect.ssl.http
+          grep "<h1>Website redirect-to-ssl</h1>" redirect.ssl.http
+
+      - name: Connect to Plural multiple times and verify it loadbalances
+        run: |
+          rm -f plural_requests
+          for i in {1..20}; do
+              docker compose exec test-box curl -s -k https://plural.example.org 2>&1 >> plural_requests
+          done
+
+          requests=$(cat plural_requests | grep "Running on" | sort | uniq | wc -l)
+          echo "Unique Servers: $requests"
+                    
+          # We should have exactly 3
+          test $requests -eq 3
+
+      - name: Cleanup
+        if: always()
+        run: docker compose down -v --remove-orphans
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
index 07ddea3..411bf7c 100644
--- a/.php-cs-fixer.php
+++ b/.php-cs-fixer.php
@@ -1,8 +1,16 @@
 <?php
-$finder = PhpCsFixer\Finder::create();
+
+declare(strict_types=1);
+
+use PhpCsFixer\Config;
+use PhpCsFixer\Finder;
+use PhpCsFixer\Runner\Parallel\ParallelConfig;
+
+$finder = Finder::create();
 $finder->in(__DIR__);
 
-return (new PhpCsFixer\Config())
+return (new Config())
+    ->setParallelConfig(new ParallelConfig(10, 20, 120))
     ->setRiskyAllowed(true)
     ->setHideProgress(false)
     ->setRules([
@@ -37,4 +45,4 @@ return (new PhpCsFixer\Config())
         'native_function_invocation' => false, // Disabled as adding count($i) -> \count($i) is annoying, but supposedly more performant
     ])
     ->setFinder($finder)
-    ;
+;
diff --git a/Dockerfile b/Dockerfile
index 4f76d66..a5c5389 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -91,11 +91,18 @@ EXPOSE 80
 EXPOSE 443
 
 # Set a healthcheck to curl the bouncer and expect a 200
+# A moderately long start period is important because while it IS serving a HTTP 200 immediately, it might not have
+# completed probing the docker socket and generating the config yet.
 HEALTHCHECK --start-period=30s \
     CMD curl -s -o /dev/null -w "200" http://localhost:80/ || exit 1
 
 # checkov:skip=CKV_DOCKER_3 This is a test container.
 FROM php:nginx as test-app
 COPY tests/testsites /app/public
-HEALTHCHECK --start-period=30s \
+HEALTHCHECK --start-period=3s --interval=3s \
     CMD curl -s -o /dev/null -w "200" http://localhost:80/ || exit 1
+
+# checkov:skip=CKV_DOCKER_7 This is a test container.
+# checkov:skip=CKV_DOCKER_3 This is a test container.
+FROM alpine as test-box
+RUN apk add --no-cache curl bash
\ No newline at end of file
diff --git a/Todo.md b/Todo.md
new file mode 100644
index 0000000..fb73c6b
--- /dev/null
+++ b/Todo.md
@@ -0,0 +1,12 @@
+# Todo List
+
+- Create an actual healthcheck endpoint. It should:
+  - Display if the initial docker socket scan & generation is complete
+  - Show Domains served by the proxy behind a per-service option flag
+    - Domains should be grouped
+    - Some statistics about the domains such as the number of instances serving it should be presented
+    - Maybe the amount of traffic being sent to it?
+- Switch to using service labels instead of envs
+- Write tests to verify the S3/Lets Encrypt functionality still works
+- Log traffic to somewhere useful
+- Add a way to write logs to external services, exposing the Monolog behavior
diff --git a/docker-compose.yml b/docker-compose.yml
index 87f5fa5..ad98c69 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,46 +1,74 @@
+networks:
+  default:
+
 services:
   bouncer:
-    image: ghcr.io/benzine-framework/bouncer:latest
     build:
+      context: .
       target: bouncer
       additional_contexts:
         - php:cli=docker-image://ghcr.io/benzine-framework/php:cli-8.2
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
-      - ./:/app
-    #    environment:
-    #      - BOUNCER_LETSENCRYPT_MODE=staging
-    #      - BOUNCER_LETSENCRYPT_EMAIL=matthew@baggett.me
-    #      - BOUNCER_S3_ENDPOINT=http://grey.ooo:9000
-    #      - BOUNCER_S3_KEY_ID=geusebio
-    #      - BOUNCER_S3_KEY_SECRET=changeme
-    #      - BOUNCER_S3_BUCKET=bouncer-certificates
-    #      - BOUNCER_S3_USE_PATH_STYLE_ENDPOINT="yes"
-    ports:
-      - 127.0.99.100:80:80
-      - 127.0.99.100:443:443
-
-  web-a:
-    image: test-app-a
+      - ./src:/app/src
+      - ./templates:/app/templates
+      - ./vendor:/app/vendor
+    networks:
+      default:
+        aliases:
+          - a.example.org
+          - b.example.org
+          - plural.example.org
+          - redirect-to-ssl.example.org
+          - nope.example.org
+    depends_on:
+      web-a:
+        condition: service_healthy
+      web-b:
+        condition: service_healthy
+      web-redirect-ssl:
+        condition: service_healthy
+      web-plural:
+        condition: service_healthy
+  web-a: &web
     build:
-      target: test-app-a
+      context: .
+      target: test-app
       additional_contexts:
         - php:nginx=docker-image://ghcr.io/benzine-framework/php:nginx-8.2
     volumes:
       - ./tests/testsites:/app/public
     environment:
-      - BOUNCER_DOMAIN=a.web.grey.ooo
+      - BOUNCER_DOMAIN=a.example.org
       - BOUNCER_TARGET_PORT=80
       - SITE_NAME=A
+    networks:
+      - default
   web-b:
-    image: test-app-b
-    build:
-      target: test-app-b
-      additional_contexts:
-        - php:nginx=docker-image://ghcr.io/benzine-framework/php:nginx-8.2
-    volumes:
-      - ./tests/testsites:/app/public
+    <<: *web
     environment:
-      - BOUNCER_DOMAIN=b.web.grey.ooo
+      - BOUNCER_DOMAIN=b.example.org
       - BOUNCER_TARGET_PORT=80
       - SITE_NAME=B
+  web-plural:
+    <<: *web
+    environment:
+      - BOUNCER_DOMAIN=plural.example.org
+      - BOUNCER_TARGET_PORT=80
+      - SITE_NAME=plural
+    deploy:
+      replicas: 3
+  web-redirect-ssl:
+    <<: *web
+    environment:
+      - BOUNCER_DOMAIN=redirect-to-ssl.example.org
+      - BOUNCER_TARGET_PORT=80
+      - SITE_NAME=redirect-to-ssl
+      - BOUNCER_ALLOW_NON_SSL=false
+  test-box:
+    build:
+      context: .
+      target: test-box
+    command: ["tail", "-f", "/dev/null"]
+    networks:
+      - default
diff --git a/src/Bouncer.php b/src/Bouncer.php
index 33ae816..d2ffd25 100644
--- a/src/Bouncer.php
+++ b/src/Bouncer.php
@@ -49,6 +49,7 @@ class Bouncer
     private ?int $lastUpdateEpoch                  = null;
     private int $maximumNginxConfigCreationNotices = 15;
     private Settings $settings;
+    private bool $testMode;
 
     private const DEFAULT_DOCKER_SOCKET          = '/var/run/docker.sock';
     private const FILESYSTEM_CONFIG_DIR          = '/etc/nginx/sites-enabled';
@@ -110,6 +111,8 @@ class Bouncer
                 )
             );
         }
+
+        $this->setTestMode(isset($this->environment['TEST_MODE']));
     }
 
     public function getMaximumNginxConfigCreationNotices(): int
@@ -160,6 +163,21 @@ class Bouncer
         return $this;
     }
 
+    public function isTestMode(): bool
+    {
+        return $this->testMode;
+    }
+
+    public function setTestMode(bool $testMode): Bouncer
+    {
+        $this->testMode = $testMode;
+        if ($this->testMode) {
+            $this->logger->critical('Test mode is enabled. It will immediately crash out upon completion of 1 cycle.', ['emoji' => Emoji::warning()]);
+        }
+
+        return $this;
+    }
+
     /**
      * @return Target[]
      *
@@ -206,32 +224,45 @@ class Bouncer
 
                 if (!empty($container['NetworkSettings']['IPAddress'])) {
                     // As per docker service
-                    $bouncerTarget->setEndpointHostnameOrIp($container['NetworkSettings']['IPAddress']);
+                    $bouncerTarget->setEndpoints([$container['NetworkSettings']['IPAddress']]);
                 } else {
                     // As per docker compose
                     $networks = array_values($container['NetworkSettings']['Networks']);
-                    $bouncerTarget->setEndpointHostnameOrIp($networks[0]['IPAddress']);
+                    $bouncerTarget->setEndpoints([$networks[0]['IPAddress']]);
                 }
 
-                $bouncerTarget->setTargetPath(sprintf('http://%s:%d', $bouncerTarget->getEndpointHostnameOrIp(), $bouncerTarget->getPort() >= 0 ? $bouncerTarget->getPort() : 80));
-
                 $bouncerTarget->setUseGlobalCert($this->isUseGlobalCert());
 
-                $valid = $bouncerTarget->isEndpointValid();
-                // $this->logger->debug(sprintf(
-                //    '%s Decided that %s has the endpoint %s and it %s.',
-                //    Emoji::magnifyingGlassTiltedLeft(),
-                //    $bouncerTarget->getName(),
-                //    $bouncerTarget->getEndpointHostnameOrIp(),
-                //    $valid ? 'is valid' : 'is not valid'
-                // ));
-                if ($valid) {
+                // if this bouncerTarget already exists, merge it in instead of adding it.
+                foreach ($bouncerTargets as $existing) {
+                    if (isset($bouncerTarget) && $existing->getDomains() == $bouncerTarget->getDomains()) {
+                        $this->logger->debug('Found another instance of the same service, merging them together.', ['emoji' => Emoji::cupcake()]);
+                        $existing->setEndpoints(array_merge($existing->getEndpoints(), $bouncerTarget->getEndpoints()));
+                        unset($bouncerTarget);
+                    }
+                }
+                if (isset($bouncerTarget)) {
                     $bouncerTargets[] = $bouncerTarget;
                 }
             }
         }
 
-        return $bouncerTargets;
+        $validBouncerTargets = [];
+        foreach ($bouncerTargets as $bouncerTarget) {
+            $valid = $bouncerTarget->isEndpointValid();
+            // $this->logger->debug(sprintf(
+            //    '%s Decided that %s has the endpoint %s and it %s.',
+            //    Emoji::magnifyingGlassTiltedLeft(),
+            //    $bouncerTarget->getName(),
+            //    $bouncerTarget->getEndpointHostnameOrIp(),
+            //    $valid ? 'is valid' : 'is not valid'
+            // ));
+            if ($valid) {
+                $validBouncerTargets[] = $bouncerTarget;
+            }
+        }
+
+        return $validBouncerTargets;
     }
 
     public function findContainersSwarmMode(): array
@@ -288,10 +319,10 @@ class Bouncer
                         continue;
                     }
                     if ($bouncerTarget->isPortSet()) {
-                        $bouncerTarget->setEndpointHostnameOrIp($service['Spec']['Name']);
+                        $bouncerTarget->setEndpoints([$service['Spec']['Name']]);
                         // $this->logger->info('{label}: Ports for {target_name} has been explicitly set to {host}:{port}.', ['emoji' => Emoji::warning().' ', 'target_name' => $bouncerTarget->getName(), 'host' => $bouncerTarget->getEndpointHostnameOrIp(), 'port' => $bouncerTarget->getPort()]);
                     } elseif (isset($service['Endpoint']['Ports'])) {
-                        $bouncerTarget->setEndpointHostnameOrIp('172.17.0.1');
+                        $bouncerTarget->setEndpoints(['172.17.0.1']);
                         $bouncerTarget->setPort(intval($service['Endpoint']['Ports'][0]['PublishedPort']));
                     } else {
                         $this->logger->warning('{label}: ports block missing for {target_name}. Try setting BOUNCER_TARGET_PORT.', ['emoji' => Emoji::warning() . ' Bouncer.php', 'label' => $bouncerTarget->getLabel(), 'target_name' => $bouncerTarget->getName()]);
@@ -303,28 +334,39 @@ class Bouncer
 
                         continue;
                     }
-                    $bouncerTarget->setTargetPath(sprintf('http://%s:%d', $bouncerTarget->getEndpointHostnameOrIp(), $bouncerTarget->getPort()));
-
                     $bouncerTarget->setUseGlobalCert($this->isUseGlobalCert());
 
-                    // @phpstan-ignore-next-line MB: I'm not sure you're right about ->hasCustomNginxConfig only returning false, Stan..
-                    if ($bouncerTarget->isEndpointValid() || $bouncerTarget->hasCustomNginxConfig()) {
-                        $bouncerTargets[] = $bouncerTarget;
-                    } else {
-                        $this->logger->debug(
-                            'Decided that {target_name} has the endpoint {endpoint} and it is not valid.',
-                            [
-                                'emoji'       => Emoji::magnifyingGlassTiltedLeft(),
-                                'target_name' => $bouncerTarget->getName(),
-                                'endpoint'    => $bouncerTarget->getEndpointHostnameOrIp(),
-                            ]
-                        );
+                    // if this bouncerTarget already exists, merge it in instead of adding it.
+                    foreach ($bouncerTargets as $existing) {
+                        if ($existing->getDomains() == $bouncerTarget->getDomains()) {
+                            $this->logger->debug('Found another instance of the same service, merging them together.', ['emoji' => Emoji::cupcake()]);
+                            $existing->setEndpoints(array_merge($existing->getEndpoints(), $bouncerTarget->getEndpoints()));
+                            unset($bouncerTarget);
+                        }
                     }
                 }
             }
         }
 
-        return $bouncerTargets;
+        // Iterate over bouncers and check validity
+        $validBouncerTargets = [];
+        foreach ($bouncerTargets as $bouncerTarget) {
+            // @phpstan-ignore-next-line MB: I'm not sure you're right about ->hasCustomNginxConfig only returning false, Stan..
+            if ($bouncerTarget->isEndpointValid() || $bouncerTarget->hasCustomNginxConfig()) {
+                $validBouncerTargets[] = $bouncerTarget;
+            } else {
+                $this->logger->debug(
+                    'Decided that {target_name} has the endpoint {endpoint} and it is not valid.',
+                    [
+                        'emoji'       => Emoji::magnifyingGlassTiltedLeft(),
+                        'target_name' => $bouncerTarget->getName(),
+                        'endpoint'    => $bouncerTarget->getEndpoints()[0],
+                    ]
+                );
+            }
+        }
+
+        return $validBouncerTargets;
     }
 
     public function run(): void
@@ -512,10 +554,7 @@ class Bouncer
         } elseif ($this->forcedUpdateIntervalSeconds > 0 && $this->lastUpdateEpoch <= time() - $this->forcedUpdateIntervalSeconds) {
             $this->logger->warning('Forced update interval of {interval_seconds} seconds has been reached, forcing update.', ['emoji' => Emoji::watch(), 'interval_seconds' => $this->forcedUpdateIntervalSeconds]);
             $isTainted = true;
-        } elseif ($this->previousContainerState === []) {
-            $this->logger->warning('Initial state has not been set, forcing update.', ['emoji' => Emoji::watch()]);
-            $isTainted = true;
-        } elseif ($this->previousSwarmState === []) {
+        } elseif ($this->previousContainerState === [] && $this->previousSwarmState === []) {
             $this->logger->warning('Initial swarm state has not been set, forcing update.', ['emoji' => Emoji::watch()]);
             $isTainted = true;
         }
@@ -663,6 +702,13 @@ class Bouncer
             return;
         }
 
+        if ($this->isTestMode()) {
+            $this->logger->info('Test mode enabled, not restarting nginx. Infact, I\'ll die now..', ['emoji' => Emoji::warning() . ' Bouncer.php']);
+            $this->dumpConfigs();
+
+            exit(0);
+        }
+
         // Wait for next change
         $this->waitUntilContainerChange();
     }
@@ -924,7 +970,6 @@ class Bouncer
             $target->setUseTemporaryCert(false);
             $this->generateNginxConfig($target);
         }
-
         $this->restartNginx();
     }
 
@@ -937,4 +982,18 @@ class Bouncer
         $nginxRestartOutput = $shell->run($command);
         $this->logger->debug('Nginx restarted {restart_output}', ['restart_output' => $nginxRestartOutput, 'emoji' => Emoji::partyPopper()]);
     }
+
+    private function dumpConfigs(): void
+    {
+        // Dump the contents of every .conf file in /etc/nginx/sites-enabled
+        foreach ($this->configFilesystem->listContents('') as $file) {
+            if ($file['type'] == 'file' && pathinfo($file['path'], PATHINFO_EXTENSION) == 'conf') {
+                if ($file['path'] == 'default.conf') {
+                    continue;
+                }
+                $this->logger->info('Dumping {file}', ['emoji' => Emoji::pencil() . ' Bouncer.php', 'file' => $file['path']]);
+                echo $this->configFilesystem->read($file['path']);
+            }
+        }
+    }
 }
diff --git a/src/Target.php b/src/Target.php
index 12b783b..c2b5acf 100644
--- a/src/Target.php
+++ b/src/Target.php
@@ -14,10 +14,9 @@ class Target
     private string $id;
     private ?string $label = null;
     private array $domains;
-    private string $endpointHostnameOrIp;
+    private array $endpoints  = [];
     private ?int $port        = null;
     private bool $letsEncrypt = false;
-    private string $targetPath;
     private bool $allowNonSSL;
     private bool $useTemporaryCert       = false;
     private bool $useGlobalCert          = false;
@@ -55,8 +54,9 @@ class Target
             'name'                     => $this->getName(),
             'label'                    => $this->getLabel(),
             'serverName'               => $this->getNginxServerName(),
+            'backends'                 => $this->getBackends(),
+            'backendName'              => $this->getBackendName(),
             'certType'                 => $this->getTypeCertInUse()->name,
-            'targetPath'               => $this->getTargetPath(),
             'customCertFile'           => $this->getCustomCertPath(),
             'customCertKeyFile'        => $this->getCustomCertKeyPath(),
             'useCustomCert'            => $this->isUseCustomCert(),
@@ -318,6 +318,11 @@ class Target
         return implode(' ', $this->getNginxServerNames());
     }
 
+    public function getBackendName()
+    {
+        return sprintf('backend_%s', substr(md5($this->getName()), 0, 8));
+    }
+
     /**
      * @param string[] $domains
      */
@@ -341,26 +346,24 @@ class Target
         return $this;
     }
 
-    public function getTargetPath(): string
+    public function getBackends(): array
     {
-        return $this->targetPath;
+        $backends = [];
+        foreach ($this->getEndpoints() as $endpoint) {
+            $backends[] = sprintf('%s:%d', $endpoint, $this->getPort());
+        }
+
+        return $backends;
     }
 
-    public function setTargetPath(string $targetPath): self
+    public function getEndpoints(): array
     {
-        $this->targetPath = $targetPath;
-
-        return $this;
+        return $this->endpoints;
     }
 
-    public function getEndpointHostnameOrIp(): string
+    public function setEndpoints(array $endpoints): self
     {
-        return $this->endpointHostnameOrIp;
-    }
-
-    public function setEndpointHostnameOrIp(string $endpointHostnameOrIp): self
-    {
-        $this->endpointHostnameOrIp = $endpointHostnameOrIp;
+        $this->endpoints = $endpoints;
 
         return $this;
     }
@@ -422,24 +425,25 @@ class Target
 
     public function isEndpointValid(): bool
     {
-        // Is it just an IP?
-        if (filter_var($this->getEndpointHostnameOrIp(), FILTER_VALIDATE_IP)) {
-            // $this->logger->debug(sprintf('%s isEndpointValid: %s is a normal IP', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp()));
+        foreach ($this->getEndpoints() as $endpoint) {
+            // Is it just an IP?
+            if (filter_var($endpoint, FILTER_VALIDATE_IP)) {
+                // $this->logger->debug(sprintf('%s isEndpointValid: %s is a normal IP', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp()));
 
-            return true;
+                return true;
+            }
+
+            // Is it a Hostname that resolves?
+            $resolved = gethostbyname($endpoint);
+            if (filter_var($resolved, FILTER_VALIDATE_IP)) {
+                // $this->logger->critical(sprintf('%s isEndpointValid: %s is a hostname that resolves to a normal IP %s', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp(), $resolved));
+
+                return true;
+            }
+            $this->logger->critical('isEndpointValid: {endpoint} is a hostname that does not resolve', ['emoji' => Emoji::magnifyingGlassTiltedRight(), 'endpoint' => $endpoint]);
+            $this->setRequiresForcedScanning(true);
         }
 
-        // Is it a Hostname that resolves?
-        $resolved = gethostbyname($this->getEndpointHostnameOrIp());
-        if (filter_var($resolved, FILTER_VALIDATE_IP)) {
-            // $this->logger->critical(sprintf('%s isEndpointValid: %s is a hostname that resolves to a normal IP %s', Emoji::magnifyingGlassTiltedRight(), $this->getEndpointHostnameOrIp(), $resolved));
-
-            return true;
-        }
-
-        $this->logger->critical('isEndpointValid: {endpoint} is a hostname that does not resolve', ['emoji' => Emoji::magnifyingGlassTiltedRight(), 'endpoint' => $this->getEndpointHostnameOrIp()]);
-        $this->setRequiresForcedScanning(true);
-
         return false;
     }
 
diff --git a/templates/NginxTemplate.twig b/templates/NginxTemplate.twig
index 85babee..ccf84cd 100644
--- a/templates/NginxTemplate.twig
+++ b/templates/NginxTemplate.twig
@@ -1,3 +1,9 @@
+upstream {{ backendName }} {
+  least_conn;
+{% for backend in backends %}
+  server {{ backend }};
+{% endfor %}
+}
 server {
 {% if allowNonSSL %}
   # Non-SSL Traffic is allowed
@@ -39,7 +45,7 @@ server {
 {% endif %}
 
     # Server to send the request on to
-    proxy_pass                  "{{ targetPath }}";
+    proxy_pass                  "http://{{ backendName }}";
 
     # Standard headers setting origin data
     proxy_set_header            X-Real-IP $remote_addr;
diff --git a/tests/testsites/index.php b/tests/testsites/index.php
index cadbb80..a55b080 100644
--- a/tests/testsites/index.php
+++ b/tests/testsites/index.php
@@ -2,6 +2,6 @@
 
 declare(strict_types=1);
 $environment = array_merge($_ENV, $_SERVER);
-$site        = $environment['SITE_NAME']   ?? 'unknown';
-$server      = $environment['SERVER_NAME'] ?? gethostname();
-printf('<h1>Website %s</h1><p>Running on %s</p>', $site, $server);
+$site        = $environment['SITE_NAME'] ?? 'unknown';
+$server      = $environment['HOSTNAME']  ?? gethostname();
+printf("<h1>Website %s</h1>\n<p>Running on %s</p>\n", $site, $server);