feat: prepare demo instance

refactor: move REDIS_URL in envvar

ci: add deploy.yml

ci: update deploy.yml

ci: update deploy.yml

chore: update Exception list in sentry.yaml

ci: update deploy.yml
This commit is contained in:
Maël Gangloff
2025-10-03 20:40:21 +02:00
parent 76377116ce
commit d5529a1678
14 changed files with 603 additions and 13 deletions

6
.env
View File

@@ -94,3 +94,9 @@ INFLUXDB_URL=http://localhost:8086
INFLUXDB_TOKEN=TOKEN
INFLUXDB_BUCKET=domainwatchdog
INFLUXDB_ORG=domainwatchdog
###> sentry/sentry-symfony ###
SENTRY_DSN=
###< sentry/sentry-symfony ###
REDIS_URL=

30
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Deploy Demo
on:
push:
branches: [demo-instance]
concurrency: production_environment
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: Domain Watchdog Demo
url: https://demo.domainwatchdog.eu
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.4"
- name: Install dependencies
run: composer install
- name: Deploy
uses: deployphp/action@v1
with:
private-key: ${{ secrets.DEPLOYER_PRIVATE_KEY }}
dep: deploy

View File

@@ -44,6 +44,7 @@
"psr/http-client": "^1.0",
"runtime/frankenphp-symfony": "^0.2.0",
"scienta/doctrine-json-functions": "^6.3",
"sentry/sentry-symfony": "^5.6",
"symfony/asset": "7.3.*",
"symfony/asset-mapper": "7.3.*",
"symfony/cache": "7.3.*",
@@ -148,6 +149,7 @@
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^4.2",
"deployer/deployer": "^7.5",
"friendsofphp/php-cs-fixer": "^3.61",
"justinrainbow/json-schema": "^6.6",
"phpstan/phpstan": "^1.11",

393
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "eda6c30d2f98c773780d758d5129f17e",
"content-hash": "815a28999cc82c44dc3555d9bc10ccd8",
"packages": [
{
"name": "api-platform/core",
@@ -1997,6 +1997,66 @@
},
"time": "2025-06-26T05:12:59+00:00"
},
{
"name": "jean85/pretty-package-versions",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a",
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"rector/rector": "^2.0",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A library to get pretty versions strings of installed dependencies",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1"
},
"time": "2025-03-19T14:43:43+00:00"
},
{
"name": "knpuniversity/oauth2-client-bundle",
"version": "v2.20.1",
@@ -4262,6 +4322,196 @@
},
"time": "2024-11-08T12:33:19+00:00"
},
{
"name": "sentry/sentry",
"version": "4.19.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "1c21d60bebe67c0122335bd3fe977990435af0a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/1c21d60bebe67c0122335bd3fe977990435af0a3",
"reference": "1c21d60bebe67c0122335bd3fe977990435af0a3",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"guzzlehttp/psr7": "^1.8.4|^2.1.1",
"jean85/pretty-package-versions": "^1.5|^2.0.4",
"php": "^7.2|^8.0",
"psr/log": "^1.0|^2.0|^3.0",
"symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0|^8.0"
},
"conflict": {
"raven/raven": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"guzzlehttp/promises": "^2.0.3",
"guzzlehttp/psr7": "^1.8.4|^2.1.1",
"monolog/monolog": "^1.6|^2.0|^3.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5|^9.6",
"vimeo/psalm": "^4.17"
},
"suggest": {
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler."
},
"type": "library",
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"Sentry\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sentry",
"email": "accounts@sentry.io"
}
],
"description": "PHP SDK for Sentry (http://sentry.io)",
"homepage": "http://sentry.io",
"keywords": [
"crash-reporting",
"crash-reports",
"error-handler",
"error-monitoring",
"log",
"logging",
"profiling",
"sentry",
"tracing"
],
"support": {
"issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.19.1"
},
"funding": [
{
"url": "https://sentry.io/",
"type": "custom"
},
{
"url": "https://sentry.io/pricing/",
"type": "custom"
}
],
"time": "2025-12-02T15:57:41+00:00"
},
{
"name": "sentry/sentry-symfony",
"version": "5.8.2",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-symfony.git",
"reference": "fb03d506c575cd1cb5274774d0dd968938150982"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-symfony/zipball/fb03d506c575cd1cb5274774d0dd968938150982",
"reference": "fb03d506c575cd1cb5274774d0dd968938150982",
"shasum": ""
},
"require": {
"guzzlehttp/psr7": "^2.1.1",
"jean85/pretty-package-versions": "^1.5||^2.0",
"php": "^7.2||^8.0",
"sentry/sentry": "^4.19.1",
"symfony/cache-contracts": "^1.1||^2.4||^3.0",
"symfony/config": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/console": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/dependency-injection": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/event-dispatcher": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/http-kernel": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/polyfill-php80": "^1.22",
"symfony/psr-http-message-bridge": "^1.2||^2.0||^6.4||^7.0||^8.0",
"symfony/yaml": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0"
},
"require-dev": {
"doctrine/dbal": "^2.13||^3.3||^4.0",
"doctrine/doctrine-bundle": "^2.6||^3.0",
"friendsofphp/php-cs-fixer": "^2.19||^3.40",
"masterminds/html5": "^2.8",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.12.5",
"phpstan/phpstan-phpunit": "1.4.0",
"phpstan/phpstan-symfony": "1.4.10",
"phpunit/phpunit": "^8.5.40||^9.6.21",
"symfony/browser-kit": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/cache": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/dom-crawler": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/framework-bundle": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/http-client": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/messenger": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/monolog-bundle": "^3.4||^4.0",
"symfony/phpunit-bridge": "^5.2.6||^6.0||^7.0||^8.0",
"symfony/process": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/security-core": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/security-http": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"symfony/twig-bundle": "^4.4.20||^5.0.11||^6.0||^7.0||^8.0",
"vimeo/psalm": "^4.3||^5.16.0"
},
"suggest": {
"doctrine/doctrine-bundle": "Allow distributed tracing of database queries using Sentry.",
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler.",
"symfony/cache": "Allow distributed tracing of cache pools using Sentry.",
"symfony/twig-bundle": "Allow distributed tracing of Twig template rendering using Sentry."
},
"type": "symfony-bundle",
"autoload": {
"files": [
"src/aliases.php"
],
"psr-4": {
"Sentry\\SentryBundle\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sentry",
"email": "accounts@sentry.io"
}
],
"description": "Symfony integration for Sentry (http://getsentry.com)",
"homepage": "http://getsentry.com",
"keywords": [
"errors",
"logging",
"sentry",
"symfony"
],
"support": {
"issues": "https://github.com/getsentry/sentry-symfony/issues",
"source": "https://github.com/getsentry/sentry-symfony/tree/5.8.2"
},
"funding": [
{
"url": "https://sentry.io/",
"type": "custom"
},
{
"url": "https://sentry.io/pricing/",
"type": "custom"
}
],
"time": "2025-12-04T12:34:17+00:00"
},
{
"name": "symfony/asset",
"version": "v7.3.0",
@@ -8565,6 +8815,93 @@
],
"time": "2025-12-05T13:52:40+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
"version": "v7.3.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
"reference": "0c0c89215703cc91cee31e9da3cbf4235fc332f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/0c0c89215703cc91cee31e9da3cbf4235fc332f1",
"reference": "0c0c89215703cc91cee31e9da3cbf4235fc332f1",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/http-message": "^1.0|^2.0",
"symfony/http-foundation": "^6.4|^7.0"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-kernel": "<6.4"
},
"require-dev": {
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3",
"symfony/browser-kit": "^6.4|^7.0",
"symfony/config": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/framework-bundle": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\PsrHttpMessage\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "PSR HTTP message bridge",
"homepage": "https://symfony.com",
"keywords": [
"http",
"http-message",
"psr-17",
"psr-7"
],
"support": {
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.3.8"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-11-12T19:00:12+00:00"
},
{
"name": "symfony/pushover-notifier",
"version": "v7.3.0",
@@ -11757,6 +12094,60 @@
],
"time": "2024-05-06T16:37:16+00:00"
},
{
"name": "deployer/deployer",
"version": "v7.5.12",
"source": {
"type": "git",
"url": "https://github.com/deployphp/deployer.git",
"reference": "efc71dac9ccc86b3f9946e75d50cb106b775aae2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/deployphp/deployer/zipball/efc71dac9ccc86b3f9946e75d50cb106b775aae2",
"reference": "efc71dac9ccc86b3f9946e75d50cb106b775aae2",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^8.0|^7.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.64",
"pestphp/pest": "^3.3",
"phpstan/phpstan": "^1.4",
"phpunit/php-code-coverage": "^11.0",
"phpunit/phpunit": "^11.4"
},
"bin": [
"bin/dep"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anton Medvedev",
"email": "anton@medv.io"
}
],
"description": "Deployment Tool",
"homepage": "https://deployer.org",
"support": {
"docs": "https://deployer.org/docs",
"issues": "https://github.com/deployphp/deployer/issues",
"source": "https://github.com/deployphp/deployer"
},
"funding": [
{
"url": "https://github.com/sponsors/antonmedv",
"type": "github"
}
],
"time": "2025-02-19T16:45:27+00:00"
},
{
"name": "doctrine/data-fixtures",
"version": "2.2.0",

View File

@@ -19,6 +19,7 @@ return [
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
Sentry\SentryBundle\SentryBundle::class => ['all' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true],
];

View File

@@ -8,8 +8,8 @@ framework:
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
app: cache.adapter.redis
default_redis_provider: '%env(REDIS_URL)%'
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu

View File

@@ -60,3 +60,10 @@ when@prod:
channels: [ deprecation ]
path: php://stderr
formatter: monolog.formatter.json
file_log:
type: rotating_file
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
max_files: 2
channels: [ "!cache", "!deprecation", "!messenger", "!security" ]

View File

@@ -0,0 +1,57 @@
sentry:
register_error_listener: false # Disables the ErrorListener to avoid duplicated log in sentry
register_error_handler: false # Disables the ErrorListener, ExceptionListener and FatalErrorListener integrations of the base PHP SDK
services:
# (Optionally) Configure the breadcrumb handler as a service (needed for the breadcrumb Monolog handler)
Sentry\Monolog\BreadcrumbHandler:
arguments:
- '@Sentry\State\HubInterface'
- !php/const Monolog\Logger::INFO # Configures the level of messages to capture as breadcrumbs
monolog:
handlers:
# (Optionally) Register the breadcrumb handler as a Monolog handler
sentry_breadcrumbs:
type: service
name: sentry_breadcrumbs
id: Sentry\Monolog\BreadcrumbHandler
# Register the handler as a Monolog handler to capture messages as events
sentry:
type: sentry
level: !php/const Monolog\Logger::ERROR # Configures the level of messages to capture as events
hub_id: Sentry\State\HubInterface
fill_extra_context: true # Enables sending monolog context to Sentry
process_psr_3_messages: false # Disables the resolution of PSR-3 placeholders in reported messages
when@prod:
sentry:
dsn: '%env(SENTRY_DSN)%'
options:
# Add request headers, cookies, IP address and the authenticated user
# see https://docs.sentry.io/platforms/php/data-management/data-collected/ for more info
# send_default_pii: true
ignore_exceptions:
- 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'
- 'Symfony\Component\Security\Core\Exception\AccessDeniedException'
- 'Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException'
- 'App\Exception\DomainNotFoundException'
- 'App\Exception\MalformedDomainException'
- 'App\Exception\TldNotSupportedException'
- 'App\Exception\UnknownRdapServerException'
# If you are using Monolog, you also need this additional configuration to log the errors correctly:
# https://docs.sentry.io/platforms/php/guides/symfony/#monolog-integration
register_error_listener: false
register_error_handler: false
# monolog:
# handlers:
# sentry:
# type: sentry
# level: !php/const Monolog\Logger::ERROR
# hub_id: Sentry\State\HubInterface
# fill_extra_context: true # Enables sending monolog context to Sentry
# process_psr_3_messages: false # Disables the resolution of PSR-3 placeholders

38
deploy.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
namespace Deployer;
require 'recipe/symfony.php';
// Config
set('repository', 'https://github.com/maelgangloff/domain-watchdog.git');
set('branch', 'demo-instance');
set('keep_releases', 1);
add('shared_files', []);
add('shared_dirs', ['node_modules', 'public/content', 'config/jwt', 'config/app']);
add('writable_dirs', []);
// Hosts
host('dw1.srv.domainwatchdog.eu')
->setPort(2004)
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/demo.domainwatchdog.eu');
desc('Build frontend');
task('front:build', function () {
run("cd {{release_or_current_path}} && yarn install --no-dev && yarn run build && yarn run ttag:po2json && rm -rf node_modules");
});
desc('Restart workers');
task('workers:restart', function () {
run("cd {{release_or_current_path}} && bin/console messenger:stop-workers");
});
// Hooks
after('deploy:failed', 'deploy:unlock');
after('deploy:vendors', 'database:migrate');
after('deploy:vendors', 'front:build');
after('deploy:unlock', 'workers:restart');

View File

@@ -1,2 +1,5 @@
User-agent: *
Disallow: /
User-agent: Twitterbot
Allow: /images
User-agent: facebookexternalhit
Allow: /images

View File

@@ -5,6 +5,7 @@ namespace App\MessageHandler;
use App\Message\UpdateRdapServers;
use App\Repository\DomainRepository;
use App\Service\OfficialDataService;
use Sentry\CheckInStatus;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
@@ -13,6 +14,8 @@ use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use function Sentry\captureCheckIn;
#[AsMessageHandler]
final readonly class UpdateRdapServersHandler
{
@@ -32,6 +35,11 @@ final readonly class UpdateRdapServersHandler
*/
public function __invoke(UpdateRdapServers $message): void
{
$checkInId = captureCheckIn(
slug: 'update-rdap-servers',
status: CheckInStatus::inProgress()
);
/** @var \Throwable[] $throws */
$throws = [];
@@ -75,7 +83,18 @@ final readonly class UpdateRdapServersHandler
}
if (!empty($throws)) {
captureCheckIn(
slug: 'update-rdap-servers',
status: CheckInStatus::error(),
checkInId: $checkInId,
);
throw $throws[0];
}
captureCheckIn(
slug: 'update-rdap-servers',
status: CheckInStatus::ok(),
checkInId: $checkInId,
);
}
}

View File

@@ -21,7 +21,7 @@ final readonly class ProcessWatchlistSchedule implements ScheduleProviderInterfa
{
return (new Schedule())
->add(
RecurringMessage::every('5 minutes', new ProcessAllWatchlist()),
RecurringMessage::every('5 seconds', new ProcessAllWatchlist()),
)
->stateful($this->cache);
}

View File

@@ -147,6 +147,18 @@
"tests/bootstrap.php"
]
},
"sentry/sentry-symfony": {
"version": "5.6",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "5.0",
"ref": "b6cb4b34429dadecd7187852123be19d628fa37a"
},
"files": [
"config/packages/sentry.yaml"
]
},
"symfony/asset-mapper": {
"version": "7.1",
"recipe": {

View File

@@ -5,33 +5,57 @@
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="title" content="Domain Watchdog">
<meta name="title" content="Domain Watchdog | Demo instance">
<meta name="description"
content="A standalone app that collects open access information about domain names, helping users track the history and changes associated with domain names">
<meta name="keywords" content="api, tracking, whois, domain, rdap, watchdog">
<meta property="og:type" content="website"/>
<meta property="og:title" content="Domain Watchdog"/>
<meta property="og:image" content="/images/banner.png">
<meta property="og:title" content="Domain Watchdog | Demo instance"/>
<meta property="og:image" content="https://domainwatchdog.eu/logo.png">
<meta property="og:description"
content="A standalone app that collects open access information about domain names, helping users track the history and changes associated with domain names"/>
<meta property="og:site_name" content="Domain Watchdog"/>
<meta property="twitter:card" content="summary"/>
<meta property="twitter:title" content="Domain Watchdog"/>
<meta property="twitter:title" content="Domain Watchdog | Demo instance"/>
<meta property="twitter:description"
content="A standalone app that collects open access information about domain names, helping users track the history and changes associated with domain names"/>
<meta property="twitter:image" content="/images/banner.png"/>
<meta property="twitter:image" content="https://domainwatchdog.eu/logo.png"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Domain Watchdog</title>
<title>Domain Watchdog | Demo instance</title>
<link rel="manifest" href="/manifest.json"/>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" href="https://domainwatchdog.eu/logo.png">
{{ encore_entry_link_tags('app') }}
</head>
<body>
<div id="root"></div>
{{ encore_entry_script_tags('app') }}
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
_paq.push(["trackAllContentImpressions"]);
_paq.push(['trackVisibleContentImpressions']);
_paq.push(['enableHeartBeatTimer']);
(function () {
var u = "//sonar.domainwatchdog.eu/";
_paq.push(['setTrackerUrl', u + 'sonar']);
_paq.push(['setSiteId', '1']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.async = true;
g.src = u + 'sonar.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img referrerpolicy="no-referrer-when-downgrade" src="//sonar.domainwatchdog.eu/sonar?idsite=1&amp;rec=1"
style="border:0;" alt=""/></p></noscript>
<!-- End Matomo Code -->
</body>
</html>