Files
NomadBackup/nomad_backup/calendar-proxy.hcl
2025-11-21 21:10:40 +00:00

228 lines
5.1 KiB
HCL

job "calendar-proxy" {
datacenters = ["dc1"]
type = "service"
group "web" {
count = 1
network {
port "http" {
to = 80
}
}
service {
name = "calendar-proxy"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.calendar-proxy.rule=Host(`mail.fbleagh.duckdns.org`)",
"traefik.http.routers.calendar-proxy.entrypoints=web",
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
# Nginx container
task "nginx" {
driver = "docker"
lifecycle {
hook = "prestart"
sidecar = true
}
config {
image = "nginx:alpine"
ports = ["http"]
volumes = [
"local/nginx.conf:/etc/nginx/nginx.conf",
"local/app:/var/www/html",
]
}
template {
data = <<EOF
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream php-fpm {
server 127.0.0.1:9000;
}
server {
listen 80;
server_name mail.fbleagh.duckdns.org;
root /var/www/html;
index ics.php;
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
location / {
try_files $uri $uri/ /ics.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
# Hide nginx version
server_tokens off;
}
}
EOF
destination = "local/nginx.conf"
}
template {
data = <<EOF
<?php
$url = $_GET['url'];
// Accept ICS calendar links only
$url_arr = explode('/', $url);
if ($url_arr[2] !== 'outlook.office365.com'
|| $url_arr[3] !== 'owa'
|| $url_arr[4] !== 'calendar'
|| end($url_arr) !== 'calendar.ics'
) {
http_response_code(500);
print "Error";
exit;
}
$context = stream_context_create([
"http" => [
"header" => "User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
]
]);
if (($data = @file_get_contents($url, false, $context)) === false) {
$error = error_get_last();
http_response_code(500);
print "HTTP request failed: " . $error['message'];
exit;
}
header('Content-Type: text/calendar; charset=utf-8');
print $data;
?>
EOF
destination = "local/app/ics.php"
}
resources {
cpu = 100
memory = 128
}
}
# PHP-FPM container
task "php-fpm" {
driver = "docker"
config {
image = "php:8.2-fpm-alpine"
network_mode = "container:nginx-${NOMAD_ALLOC_ID}"
volumes = [
"local/app:/var/www/html",
"local/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf",
]
}
template {
data = <<EOF
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOF
destination = "local/php-fpm.conf"
}
template {
data = <<EOF
<?php
$url = $_GET['url'];
# // Accept ICS calendar links only
# $url_arr = explode('/', $url);
# if ($url_arr[2] !== 'outlook.office365.com'
# || $url_arr[3] !== 'owa'
# || $url_arr[4] !== 'calendar'
# || end($url_arr) !== 'calendar.ics'
# ) {
# http_response_code(500);
# print "Error";
# exit;
# }
$context = stream_context_create([
"http" => [
"header" => "User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
]
]);
if (($data = @file_get_contents($url, false, $context)) === false) {
$error = error_get_last();
http_response_code(500);
print "HTTP request failed: " . $error['message'];
exit;
}
header('Content-Type: text/calendar; charset=utf-8');
print $data;
?>
EOF
destination = "local/app/ics.php"
}
resources {
cpu = 200
memory = 256
}
}
# Restart policy
restart {
attempts = 3
interval = "5m"
delay = "25s"
mode = "fail"
}
# Update strategy
update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "3m"
auto_revert = true
}
}
}