Initial commit
This commit is contained in:
commit
c3f8908cb5
8 changed files with 660 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Runtime data
|
||||
/data/
|
||||
*.db
|
||||
|
||||
# Secrets
|
||||
config/config.php
|
||||
.env
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# OS / editor
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
34
Dockerfile
Normal file
34
Dockerfile
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
FROM php:8.2-apache
|
||||
|
||||
# Install required system packages
|
||||
RUN apt-get update && apt-get install -y \
|
||||
cron \
|
||||
sqlite3 \
|
||||
libsqlite3-dev \
|
||||
pkg-config \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install pdo pdo_sqlite
|
||||
|
||||
# Enable Apache rewrite (optional)
|
||||
RUN a2enmod rewrite
|
||||
|
||||
# Copy application
|
||||
COPY index.php /var/www/html/index.php
|
||||
# COPY history.php /var/www/html/history.php
|
||||
COPY check_ssl.php /var/www/check_ssl.php
|
||||
COPY domains.txt /var/www/domains.txt
|
||||
|
||||
# Create data directory
|
||||
RUN mkdir -p /var/www/data \
|
||||
&& chown -R www-data:www-data /var/www
|
||||
|
||||
# Cron job (every 6 hours)
|
||||
RUN echo "0 */6 * * * php /var/www/check_ssl.php >> /var/log/cron.log 2>&1" \
|
||||
> /etc/cron.d/ssl \
|
||||
&& chmod 0644 /etc/cron.d/ssl \
|
||||
&& crontab /etc/cron.d/ssl
|
||||
|
||||
# Start cron + Apache
|
||||
CMD cron && apache2-foreground
|
||||
67
check_ssl.php
Normal file
67
check_ssl.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
set_time_limit(0);
|
||||
|
||||
$db = new PDO("sqlite:/var/www/data/ssl.db");
|
||||
$db->exec("
|
||||
CREATE TABLE IF NOT EXISTS certs (
|
||||
domain TEXT PRIMARY KEY,
|
||||
expires INTEGER,
|
||||
checked_at INTEGER,
|
||||
error TEXT
|
||||
)");
|
||||
|
||||
$domains = file("/var/www/domains.txt", FILE_IGNORE_NEW_LINES);
|
||||
|
||||
function check_ssl($domain) {
|
||||
$ctx = stream_context_create([
|
||||
"socket" => ["bindto" => "0.0.0.0:0"],
|
||||
"ssl" => [
|
||||
"capture_peer_cert" => true,
|
||||
"verify_peer" => false,
|
||||
"verify_peer_name" => false,
|
||||
"SNI_enabled" => true,
|
||||
"peer_name" => $domain
|
||||
]
|
||||
]);
|
||||
|
||||
$client = @stream_socket_client(
|
||||
"ssl://$domain:443",
|
||||
$errno,
|
||||
$errstr,
|
||||
5,
|
||||
STREAM_CLIENT_CONNECT,
|
||||
$ctx
|
||||
);
|
||||
|
||||
if (!$client) return [null, $errstr];
|
||||
|
||||
$params = stream_context_get_params($client);
|
||||
if (!isset($params["options"]["ssl"]["peer_certificate"])) {
|
||||
return [null, "No certificate"];
|
||||
}
|
||||
|
||||
$cert = openssl_x509_parse($params["options"]["ssl"]["peer_certificate"]);
|
||||
return [$cert["validTo_time_t"] ?? null, null];
|
||||
}
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
[$expiry, $error] = check_ssl($domain);
|
||||
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO certs(domain, expires, checked_at, error)
|
||||
VALUES(:d,:e,:c,:er)
|
||||
ON CONFLICT(domain) DO UPDATE SET
|
||||
expires=:e, checked_at=:c, error=:er
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
":d" => $domain,
|
||||
":e" => $expiry,
|
||||
":c" => time(),
|
||||
":er" => $error
|
||||
]);
|
||||
|
||||
usleep(200000); // anti-rate-limit (0.2s)
|
||||
}
|
||||
|
||||
echo "SSL check completed\n";
|
||||
17
docker-compose.yml
Normal file
17
docker-compose.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
version: "3.9"
|
||||
|
||||
services:
|
||||
ssl-monitor:
|
||||
image: ssl-monitor:latest
|
||||
container_name: ssl-monitor
|
||||
build: .
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./config:/app/config
|
||||
environment:
|
||||
DB_PATH: /app/data/ssl.db
|
||||
ALERT_DAYS: 14
|
||||
ADMIN_EMAIL: admin@example.com
|
||||
restart: unless-stopped
|
||||
77
domains.txt
Normal file
77
domains.txt
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
cms-pews.geosphere.at
|
||||
cms-vis-pews.geosphere.at
|
||||
pews.geosphere.at
|
||||
hub-pews.geosphere.at
|
||||
cobs.geosphere.at
|
||||
swap.geosphere.at
|
||||
portale.geosphere.at
|
||||
edrop.geosphere.at
|
||||
taguing.geosphere.at
|
||||
appshiny.geosphere.at
|
||||
eshiny-proxy.geosphere.at
|
||||
klimaportal.geosphere.at
|
||||
gitlab.geosphere.at
|
||||
projects.gitlab.geosphere.at
|
||||
4cast.gitlab.geosphere.at
|
||||
ieatask51-austria.gitlab.geosphere.at
|
||||
atmoi4ren-4cast.gitlab.geosphere.at
|
||||
www.gitlab.geosphere.at
|
||||
wmo.gitlab.geosphere.at
|
||||
energyprotect.gitlab.geosphere.at
|
||||
projectpages.geosphere.at
|
||||
risklab.geosphere.at
|
||||
mapi.geosphere.at
|
||||
autodiscover.geosphere.at
|
||||
webmail.geosphere.at
|
||||
eva.geosphere.at
|
||||
self-service.geosphere.at
|
||||
vpn.geosphere.at
|
||||
www.geosphere.at
|
||||
eduid.geosphere.at
|
||||
maintenance.hub.geosphere.at
|
||||
metadata.hub.geosphere.at
|
||||
datenzentrum.geosphere.at
|
||||
s3.hub.geosphere.at
|
||||
station.api.hub.geosphere.at
|
||||
keycloak.hub.geosphere.at
|
||||
data.hub.geosphere.at
|
||||
frontend.dataset.api.staging.hub.geosphere.at
|
||||
s3direct.hub.geosphere.at
|
||||
dataset.api.hub.geosphere.at
|
||||
thredds.staging.hub.geosphere.at
|
||||
metadata.form.hub.geosphere.at
|
||||
ckan.metadata.hub.geosphere.at
|
||||
datenzentrum.hub.geosphere.at
|
||||
www.dataset.api.hub.geosphere.at
|
||||
openapi.hub.geosphere.at
|
||||
s3.staging.hub.geosphere.at
|
||||
keycloak.staging.hub.geosphere.at
|
||||
thredds.hub.geosphere.at
|
||||
public.hub.geosphere.at
|
||||
mapping.api.staging.hub.geosphere.at
|
||||
iris.geosphere.at
|
||||
catalog.geosphere.at
|
||||
geothermieatlas.geosphere.at
|
||||
meldung-geodaten.geosphere.at
|
||||
maps.geosphere.at
|
||||
resource.geosphere.at
|
||||
ardigeos.geosphere.at
|
||||
gis.geosphere.at
|
||||
smw.geosphere.at
|
||||
webstat.geosphere.at
|
||||
oculus.geosphere.at
|
||||
coturn.geosphere.at
|
||||
signaling.geosphere.at
|
||||
recording.geosphere.at
|
||||
rhea.geosphere.at
|
||||
rocky-austria.geosphere.at
|
||||
bibliothek.geosphere.at
|
||||
bibliothek-admin.geosphere.at
|
||||
bibliothek-test-admin.geosphere.at
|
||||
bibliothek-test.geosphere.at
|
||||
gitea.geosphere.at
|
||||
jobs.geosphere.at
|
||||
thesaurus.geolba.ac.at
|
||||
resource.geolba.ac.at
|
||||
gemas.geolba.ac.at
|
||||
catalog.zamg.ac.at
|
||||
235
domains_ungueltig.txt
Normal file
235
domains_ungueltig.txt
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
eon2.geosphere.at
|
||||
keycloak.production.hub-dev.geosphere.at
|
||||
k8s-prod1.geosphere.at
|
||||
zaaspure1.geosphere.at
|
||||
mx1mgmt.geosphere.at
|
||||
vsents5.geosphere.at
|
||||
zabbix.geosphere.at
|
||||
connect.geosphere.at
|
||||
www.maps.geosphere.at
|
||||
www.testmattermost.geosphere.at
|
||||
manual.k8s-review.geosphere.at
|
||||
status.staging.hub-dev.geosphere.at
|
||||
www.self-service.geosphere.at
|
||||
www.resource.geosphere.at
|
||||
data.staging.hub-dev.geosphere.at
|
||||
metadata.staging.hub-dev.geosphere.at
|
||||
backend-test.k8s-dev.geosphere.at
|
||||
jupyterhub.k8s-dev.geosphere.at
|
||||
keycloak.dhr.geosphere.at
|
||||
ise4.geosphere.at
|
||||
testgitlab.geosphere.at
|
||||
146www.geosphere.at
|
||||
foobartest123.geosphere.at
|
||||
enexyohub-dev.geosphere.at
|
||||
argocd.k8s-dev.geosphere.at
|
||||
ckan.metadata.staging.hub-dev.geosphere.at
|
||||
ise1.geosphere.at
|
||||
s3.hub-infra.geosphere.at
|
||||
www.myserver.geosphere.at
|
||||
klimaportal-dev.geosphere.at
|
||||
prod.hub-dev.geosphere.at
|
||||
openapi.staging.hub-dev.geosphere.at
|
||||
ionbe1502ilom.geosphere.at
|
||||
gsasmtp.geosphere.at
|
||||
metadata.form.staging.hub-dev.geosphere.at
|
||||
my-test.whatever.geosphere.at
|
||||
hub-staging.geosphere.at
|
||||
keycloak.hub.staging.geosphere.at
|
||||
testurl-rancher.geosphere.at
|
||||
ise3.geosphere.at
|
||||
www.webmail.geosphere.at
|
||||
ise.geosphere.at
|
||||
climate-indicators.geosphere.at
|
||||
plausible.infra.hub-dev.geosphere.at
|
||||
www.enexyohub-dev.geosphere.at
|
||||
argocd.hub-infra.geosphere.at
|
||||
vsents1.geosphere.at
|
||||
grafana.k8s-prod1.geosphere.at
|
||||
interflex.geosphere.at
|
||||
dataset.api.staging.hub-dev.geosphere.at
|
||||
grafana.k8s-staging1.geosphere.at
|
||||
radius2.geosphere.at
|
||||
k8s-staging1.geosphere.at
|
||||
www-dev.geosphere.at
|
||||
s3.hub.staging.geosphere.at
|
||||
www.harbor.geosphere.at
|
||||
enimbusd.geosphere.at
|
||||
tagui.geosphere.at
|
||||
vsenttest1.geosphere.at
|
||||
k8s-utility1.geosphere.at
|
||||
prometheus.k8s-prod1.geosphere.at
|
||||
ionbe1503ilom.geosphere.at
|
||||
www.signaling.geosphere.at
|
||||
www-dev2.geosphere.at
|
||||
rancher-dev.geosphere.at
|
||||
vsents2b-l1c.geosphere.at
|
||||
www.umwanalyse.geosphere.at
|
||||
www.geothermieatlas.geosphere.at
|
||||
satosa.k8s-dev.geosphere.at
|
||||
k8s-staging.geosphere.at
|
||||
vsentkeycloak.geosphere.at
|
||||
s3.netapp.geosphere.at
|
||||
www.nessus.geosphere.at
|
||||
www.gsasmtp.geosphere.at
|
||||
www.enimbusd.geosphere.at
|
||||
plone-backend.k8s-staging1.geosphere.at
|
||||
public.staging.hub-dev.geosphere.at
|
||||
staging.hub-dev.geosphere.at
|
||||
www.interflex.geosphere.at
|
||||
harbor-dev.k8s-dev.geosphere.at
|
||||
www.iot.geosphere.at
|
||||
mapping.api.hub.staging.geosphere.at
|
||||
thredds.production.hub-dev.geosphere.at
|
||||
test.geosphere.at
|
||||
www.prod.hub-dev.geosphere.at
|
||||
www.www-dev.geosphere.at
|
||||
rsa2.geosphere.at
|
||||
wlc1mgmt.geosphere.at
|
||||
maintenance-staging.geosphere.at
|
||||
ise1mgmt.geosphere.at
|
||||
uncached.k8s-prod1.geosphere.at
|
||||
ewww-dev.geosphere.at
|
||||
ipam.geosphere.at
|
||||
plausible.staging.hub-dev.geosphere.at
|
||||
wlc2mgmt.geosphere.at
|
||||
www.www.testseite.geosphere.at
|
||||
rsa1.geosphere.at
|
||||
www.k8s-prod1.geosphere.at
|
||||
dataset.api.production.hub-dev.geosphere.at
|
||||
metadata.form.production.hub-dev.geosphere.at
|
||||
semaphore.geosphere.at
|
||||
www.climate-indicators.geosphere.at
|
||||
foreman.k8s-dev.geosphere.at
|
||||
ise2.geosphere.at
|
||||
nessus.geosphere.at
|
||||
kafka-ui.k8s-dev.geosphere.at
|
||||
dhr-test.geosphere.at
|
||||
atom.rancher.geosphere.at
|
||||
www.enexyohub.geosphere.at
|
||||
datenzentrum-staging.geosphere.at
|
||||
|
||||
geprüft:
|
||||
jobs.geosphere.at
|
||||
ftp.geosphere.at
|
||||
go.geosphere.at
|
||||
cms-pews-test.geosphere.at
|
||||
cms-vis-pews-test.geosphere.at
|
||||
pews-test.geosphere.at
|
||||
sftp.geosphere.at
|
||||
mx1.geosphere.at
|
||||
mx2.geosphere.at
|
||||
pep725.geosphere.at
|
||||
adfs.geosphere.at
|
||||
eva-dev.geosphere.at
|
||||
iot.geosphere.at
|
||||
ns1.geosphere.at
|
||||
ns2.geosphere.at
|
||||
vdi.geosphere.at
|
||||
beta.geosphere.at
|
||||
hub.geosphere.at
|
||||
api.hub.geosphere.at
|
||||
dataset.api.staging.hub.geosphere.at
|
||||
www.klimaportal-dev.geosphere.at
|
||||
testurl-foo-rancher.geosphere.at
|
||||
keycloak.staging.hub-dev.geosphere.at
|
||||
vsents2a-l1c.geosphere.at
|
||||
radius3.geosphere.at
|
||||
harbor.geosphere.at
|
||||
datenzentrum.staging.hub-dev.geosphere.at
|
||||
k8s-review.geosphere.at
|
||||
hub-infra.geosphere.at
|
||||
openapi.production.hub-dev.geosphere.at
|
||||
s3.production.hub-dev.geosphere.at
|
||||
www2-dev.geosphere.at
|
||||
bitwarden.geosphere.at
|
||||
www.staging.hub-dev.geosphere.at
|
||||
umwanalyse.geosphere.at
|
||||
eeva.geosphere.at
|
||||
www.dhr.geosphere.at
|
||||
vsents3.geosphere.at
|
||||
vcharbor.geosphere.at
|
||||
www.testseite.geosphere.at
|
||||
epep725.geosphere.at
|
||||
cached-dev.k8s-dev.geosphere.at
|
||||
wlan.geosphere.at
|
||||
www.testgitlab.geosphere.at
|
||||
monitoring.hub-infra.geosphere.at
|
||||
dafne.dhr.geosphere.at
|
||||
www.datenzentrum-staging.geosphere.at
|
||||
gw.k8s-review.geosphere.at
|
||||
mattermost.geosphere.at
|
||||
www.recording.geosphere.at
|
||||
www.infra.hub-dev.geosphere.at
|
||||
quarantine.geosphere.at
|
||||
www.dhr-test.geosphere.at
|
||||
ionbe1501ilom.geosphere.at
|
||||
maintenance.production.hub-dev.geosphere.at
|
||||
cached-dev.k8s-prod1.geosphere.at
|
||||
testseite.geosphere.at
|
||||
eeva-dev.geosphere.at
|
||||
plausible.hub-infra.geosphere.at
|
||||
s3.infra.hub-dev.geosphere.at
|
||||
spf.geosphere.at
|
||||
thredds.hub.staging.geosphere.at
|
||||
vnessus01.geosphere.at
|
||||
api.eon2.geosphere.at
|
||||
vsents2-l2a.geosphere.at
|
||||
pdp.geosphere.at
|
||||
sentinel.geosphere.at
|
||||
www.sentinel.geosphere.at
|
||||
data.production.hub-dev.geosphere.at
|
||||
metadata.production.hub-dev.geosphere.at
|
||||
cached-dev.k8s-staging1.geosphere.at
|
||||
argocd.infra.hub-dev.geosphere.at
|
||||
uncached.k8s-staging1.geosphere.at
|
||||
station.api.staging.hub-dev.geosphere.at
|
||||
maintenance.staging.hub-dev.geosphere.at
|
||||
www.test.geosphere.at
|
||||
dafne-backend.dhr.geosphere.at
|
||||
cpm.geosphere.at
|
||||
sma1.geosphere.at
|
||||
mx2mgmt.geosphere.at
|
||||
vsenttest.geosphere.at
|
||||
www.go.geosphere.at
|
||||
radius1.geosphere.at
|
||||
cert-test.k8s-review.geosphere.at
|
||||
www.rsa2.geosphere.at
|
||||
loki.atom.rancher.geosphere.at
|
||||
ise2mgmt.geosphere.at
|
||||
prometheus.k8s-staging1.geosphere.at
|
||||
ckan.metadata.hub.staging.geosphere.at
|
||||
s3.staging.hub-dev.geosphere.at
|
||||
grafana.atom.rancher.geosphere.at
|
||||
grafana.k8s-dev.geosphere.at
|
||||
plone-backend.k8s-prod1.geosphere.at
|
||||
dhr.geosphere.at
|
||||
enexyohub.geosphere.at
|
||||
cps2.geosphere.at
|
||||
maintenance.geosphere.at
|
||||
dataset.api.hub.staging.geosphere.at
|
||||
myserver.geosphere.at
|
||||
plone-backend.k8s-dev.geosphere.at
|
||||
dafne.geosphere.at
|
||||
www.rsa1.geosphere.at
|
||||
trivy.k8s-dev.geosphere.at
|
||||
thredds.staging.hub-dev.geosphere.at
|
||||
station.api.production.hub-dev.geosphere.at
|
||||
vsentgss.geosphere.at
|
||||
cached.k8s-dev.geosphere.at
|
||||
www.mattermost.geosphere.at
|
||||
dependency-track.k8s-dev.geosphere.at
|
||||
www.harbor-dev.k8s-dev.geosphere.at
|
||||
ise3mgmt.geosphere.at
|
||||
ckan.metadata.production.hub-dev.geosphere.at
|
||||
rancher.geosphere.at
|
||||
dafne-backend.geosphere.at
|
||||
testmattermost.geosphere.at
|
||||
infra.hub-dev.geosphere.at
|
||||
irgendwas.geosphere.at
|
||||
cps1.geosphere.at
|
||||
public.production.hub-dev.geosphere.at
|
||||
itop.geosphere.at
|
||||
wifi.geosphere.at
|
||||
hub-pews-test.geosphere.at
|
||||
rocky.geosphere.at
|
||||
161
history.php
Normal file
161
history.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
$db = new PDO("sqlite:/var/www/data/ssl.db");
|
||||
|
||||
$domain = $_GET["domain"] ?? "";
|
||||
if (!$domain) die("Domain missing");
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT checked_at, expires
|
||||
FROM history
|
||||
WHERE domain = :d
|
||||
ORDER BY checked_at ASC
|
||||
");
|
||||
$stmt->execute([":d" => $domain]);
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$labels = [];
|
||||
$values = [];
|
||||
|
||||
foreach ($data as $row) {
|
||||
$labels[] = date("Y-m-d H:i", $row["checked_at"]);
|
||||
$values[] = round(($row["expires"] - $row["checked_at"]) / 86400, 1);
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SSL History – <?= htmlspecialchars($domain) ?></title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4f4f4;
|
||||
--text: #000;
|
||||
--card: #fff;
|
||||
--border: #ddd;
|
||||
--header: #222;
|
||||
--link: #0066cc;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
--bg: #121212;
|
||||
--text: #e0e0e0;
|
||||
--card: #1e1e1e;
|
||||
--border: #333;
|
||||
--header: #000;
|
||||
--link: #4ea3ff;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
background: var(--card);
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--border);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
background: var(--header);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
.ok { color: #4caf50; font-weight: bold; }
|
||||
.warn { color: #ff9800; font-weight: bold; }
|
||||
.critical { color: #f44336; font-weight: bold; }
|
||||
|
||||
.toggle {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
body { font-family: Arial; background:#f4f4f4; text-align:center }
|
||||
canvas { background:#fff; padding:20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="toggle" onclick="toggleDark()">🌙</div>
|
||||
|
||||
<script>
|
||||
function applyTheme() {
|
||||
const dark = localStorage.getItem("darkmode") === "1";
|
||||
document.body.classList.toggle("dark", dark);
|
||||
document.querySelector(".toggle").textContent = dark ? "☀️" : "🌙";
|
||||
}
|
||||
|
||||
function toggleDark() {
|
||||
localStorage.setItem(
|
||||
"darkmode",
|
||||
localStorage.getItem("darkmode") === "1" ? "0" : "1"
|
||||
);
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
applyTheme();
|
||||
</script>
|
||||
|
||||
<h2>Certificate History: <?= htmlspecialchars($domain) ?></h2>
|
||||
|
||||
<canvas id="chart" width="900" height="400"></canvas>
|
||||
|
||||
<script>
|
||||
new Chart(document.getElementById('chart'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: <?= json_encode($labels) ?>,
|
||||
datasets: [{
|
||||
label: 'Days until expiration',
|
||||
data: <?= json_encode($values) ?>,
|
||||
borderColor: getComputedStyle(document.body)
|
||||
.getPropertyValue('--link'),
|
||||
backgroundColor: 'transparent',
|
||||
tension: 0.1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
x: { ticks: { color: getComputedStyle(document.body).color } },
|
||||
y: { ticks: { color: getComputedStyle(document.body).color } }
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
labels: {
|
||||
color: getComputedStyle(document.body).color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
title: { display: true, text: 'Days Remaining' }
|
||||
},
|
||||
x: {
|
||||
title: { display: true, text: 'Check Time' }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<p><a href="/">← Back</a></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
54
index.php
Normal file
54
index.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
$db = new PDO("sqlite:/var/www/data/ssl.db");
|
||||
$rows = $db->query("SELECT * FROM certs ORDER BY expires ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SSL Monitor</title>
|
||||
<style>
|
||||
body { font-family: Arial; background:#f4f4f4 }
|
||||
table { border-collapse:collapse; width:80%; margin:auto; background:#fff }
|
||||
th,td { padding:10px; border:1px solid #ddd; text-align:center }
|
||||
th { background:#222; color:#fff }
|
||||
.ok { color:green; font-weight:bold }
|
||||
.warn { color:orange; font-weight:bold }
|
||||
.critical { color:red; font-weight:bold }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2 style="text-align:center">SSL Certificate Monitor</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Expires</th>
|
||||
<th>Days Left</th>
|
||||
<th>Status</th>
|
||||
<th>Last Check</th>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($rows as $r):
|
||||
if (!$r["expires"]) {
|
||||
echo "<tr><td>{$r['domain']}</td><td colspan=4 class='critical'>{$r['error']}</td></tr>";
|
||||
continue;
|
||||
}
|
||||
|
||||
$days = floor(($r["expires"] - time()) / 86400);
|
||||
if ($days > 30) $c="ok";
|
||||
elseif ($days > 7) $c="warn";
|
||||
else $c="critical";
|
||||
?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($r["domain"]) ?></td>
|
||||
<td><?= date("Y-m-d H:i:s", $r["expires"]) ?></td>
|
||||
<td><?= $days ?></td>
|
||||
<td class="<?= $c ?>"><?= strtoupper($c) ?></td>
|
||||
<td><?= date("Y-m-d H:i:s", $r["checked_at"]) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue