Point cron jobs at the app's own loopback address, not its public appUrl
Cron previously curled appUrl (the externally-reachable domain, with cfg.port appended when set). That meant every cron tick depended on the host being able to route back to its own public domain (hairpin NAT, not guaranteed), and whenever cfg.port was set to an externally-forwarded port nginx/caddy don't themselves listen on (e.g. the QEMU test VM's hostfwd), cron would curl a port nothing is listening on at all and fail outright. curl --resolve now pins the connection to 127.0.0.1 on the port nginx/caddy actually listen on (80, or 443 under proxy.ssl), while keeping the Host header/SNI as cfg.domain so vhost routing and cert validation still work normally. Also fixes the cron services' "after" dependency, which was hardcoded to nginx.service even when proxy.server = "caddy". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,20 @@ let
|
|||||||
lib.concatStringsSep "\n" (lib.mapAttrsToList mkEnvLine envVars) + "\n"
|
lib.concatStringsSep "\n" (lib.mapAttrsToList mkEnvLine envVars) + "\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# Cron jobs curl the app's own loopback address rather than its
|
||||||
|
# externally-reachable appUrl, on the port nginx/caddy actually listen on
|
||||||
|
# (80, or 443 when proxy.ssl -- never cfg.port, which per its own option
|
||||||
|
# doc doesn't change that). Otherwise cron would depend on the host being
|
||||||
|
# able to route back to its own public domain (hairpin NAT, not
|
||||||
|
# guaranteed) and, whenever cfg.port is set to an externally-forwarded
|
||||||
|
# port nginx/caddy don't themselves listen on (e.g. the QEMU test VM's
|
||||||
|
# hostfwd), would curl a port nothing is listening on at all. curl's
|
||||||
|
# --resolve pins the connection to 127.0.0.1 while keeping the
|
||||||
|
# Host header/SNI as cfg.domain, so vhost routing and cert validation
|
||||||
|
# still work normally.
|
||||||
|
cronPort = if cfg.proxy.ssl then 443 else 80;
|
||||||
|
cronUrl = path: "${scheme}://${cfg.domain}:${toString cronPort}${path}";
|
||||||
|
|
||||||
# curl'd cron endpoints -> (name, path, calendar spec)
|
# curl'd cron endpoints -> (name, path, calendar spec)
|
||||||
cronjobs = {
|
cronjobs = {
|
||||||
"tasks-overdue" = { path = "/cronjob/tasks/overdue"; when = "*-*-* 06,18:00:00"; };
|
"tasks-overdue" = { path = "/cronjob/tasks/overdue"; when = "*-*-* 06,18:00:00"; };
|
||||||
@@ -424,12 +438,13 @@ in {
|
|||||||
} // (lib.mapAttrs' (name: job:
|
} // (lib.mapAttrs' (name: job:
|
||||||
lib.nameValuePair "hortusfox-cron-${name}" {
|
lib.nameValuePair "hortusfox-cron-${name}" {
|
||||||
description = "HortusFox cronjob: ${name}";
|
description = "HortusFox cronjob: ${name}";
|
||||||
after = [ "nginx.service" ];
|
after = [ "${cfg.proxy.server}.service" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
ExecStart = "${pkgs.curl}/bin/curl -fsS --max-time 300 "
|
ExecStart = "${pkgs.curl}/bin/curl -fsS --max-time 300 "
|
||||||
+ "${appUrl}${job.path}";
|
+ "--resolve ${cfg.domain}:${toString cronPort}:127.0.0.1 "
|
||||||
|
+ "${cronUrl job.path}";
|
||||||
};
|
};
|
||||||
}) cronjobs);
|
}) cronjobs);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user