mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-06-16 22:54:12 +00:00
feat(#72): install ntfy on every node, drop --with-ntfy gating
ntfy is now part of the standard node install, just like Caddy. The binary, /etc/ntfy/server.yml, and the Caddy push.<dnsZone> reverse- proxy block are written unconditionally on every node, and the ntfy.service starts as part of the standard service order. Why uniform: ntfy listens on 127.0.0.1:NtfyListenPort only, reachable exclusively via the local Caddy reverse-proxy block. Nodes that don't serve a public push.* DNS entry just have an idle ntfy with no inbound traffic — zero operational cost, zero attack surface change. Removing the flag means no per-node toggling, no preference drift between nodes, no "did we remember to set --with-ntfy" mistakes when DNS topology changes (e.g. promoting a node to nameserver later). Removed: - NodePreferences.NtfyHost (yaml: ntfy_host) - ProductionSetup.isNtfyHost field, SetNtfyHost, IsNtfyHost - install/flags.go --with-ntfy + NtfyHost field - upgrade/flags.go --with-ntfy + NtfyHost field + isFlagPassed helper (was only used for --with-ntfy tri-state semantics) - upgrade/orchestrator.go preference-load and persist for ntfy - upgrade/remote.go --with-ntfy forwarding Phase 2 always calls InstallNtfy. Phase 4 always calls EnableCaddyNtfyProxy + ConfigureNtfy. Phase 5 always enables ntfy.service. Phase 5b always starts ntfy.service. VERSION bumped to 0.122.16.
This commit is contained in:
parent
8c37ef547e
commit
8b4abb7eef
@ -15,7 +15,6 @@ type Flags struct {
|
||||
DryRun bool
|
||||
SkipChecks bool
|
||||
Nameserver bool // Make this node a nameserver (runs CoreDNS + Caddy)
|
||||
NtfyHost bool // Host the self-hosted ntfy server on this node (feature #72)
|
||||
JoinAddress string // HTTPS URL of existing node (e.g., https://node1.dbrs.space)
|
||||
Token string // Invite token for joining (from orama invite)
|
||||
ClusterSecret string // Deprecated: use --token instead
|
||||
@ -65,7 +64,6 @@ func ParseFlags(args []string) (*Flags, error) {
|
||||
fs.BoolVar(&flags.DryRun, "dry-run", false, "Show what would be done without making changes")
|
||||
fs.BoolVar(&flags.SkipChecks, "skip-checks", false, "Skip minimum resource checks (RAM/CPU)")
|
||||
fs.BoolVar(&flags.Nameserver, "nameserver", false, "Make this node a nameserver (runs CoreDNS + Caddy)")
|
||||
fs.BoolVar(&flags.NtfyHost, "with-ntfy", false, "Host the self-hosted ntfy server (feature #72; usually colocated with --nameserver on devnet)")
|
||||
|
||||
// Cluster join flags
|
||||
fs.StringVar(&flags.JoinAddress, "join", "", "Join existing cluster via HTTPS URL (e.g. https://node1.dbrs.space)")
|
||||
|
||||
@ -46,7 +46,6 @@ func NewOrchestrator(flags *Flags) (*Orchestrator, error) {
|
||||
|
||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.SkipChecks)
|
||||
setup.SetNameserver(flags.Nameserver)
|
||||
setup.SetNtfyHost(flags.NtfyHost)
|
||||
|
||||
// Configure Anyone mode
|
||||
if flags.AnyoneRelay && flags.AnyoneClient {
|
||||
|
||||
@ -12,7 +12,6 @@ type Flags struct {
|
||||
RestartServices bool
|
||||
SkipChecks bool
|
||||
Nameserver *bool // Pointer so we can detect if explicitly set vs default
|
||||
NtfyHost *bool // Feature #72: nil = use saved preference; non-nil = explicit override
|
||||
|
||||
// Remote upgrade flags
|
||||
Env string // Target environment for remote rolling upgrade
|
||||
@ -51,8 +50,6 @@ func ParseFlags(args []string) (*Flags, error) {
|
||||
|
||||
// Nameserver flag - use pointer to detect if explicitly set
|
||||
nameserver := fs.Bool("nameserver", false, "Make this node a nameserver (uses saved preference if not specified)")
|
||||
// Ntfy host flag (feature #72) — same pattern, sticks via preferences.yaml.
|
||||
ntfyHost := fs.Bool("with-ntfy", false, "Host the self-hosted ntfy server on this node (uses saved preference if not specified)")
|
||||
|
||||
// Anyone flags
|
||||
fs.BoolVar(&flags.AnyoneClient, "anyone-client", false, "Install Anyone as client-only (SOCKS5 proxy on port 9050, no relay)")
|
||||
@ -78,25 +75,7 @@ func ParseFlags(args []string) (*Flags, error) {
|
||||
if *nameserver {
|
||||
flags.Nameserver = nameserver
|
||||
}
|
||||
// Set ntfy_host only when explicitly passed (default false != "use saved").
|
||||
// Without explicit set, the orchestrator reads the saved preference.
|
||||
if isFlagPassed(fs, "with-ntfy") {
|
||||
flags.NtfyHost = ntfyHost
|
||||
}
|
||||
|
||||
return flags, nil
|
||||
}
|
||||
|
||||
// isFlagPassed reports whether the named flag was explicitly set on
|
||||
// the command line, not just defaulted. Used to distinguish "user
|
||||
// didn't say anything; honor saved preference" from "user wrote
|
||||
// --with-ntfy=false; turn it OFF".
|
||||
func isFlagPassed(fs *flag.FlagSet, name string) bool {
|
||||
passed := false
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
if f.Name == name {
|
||||
passed = true
|
||||
}
|
||||
})
|
||||
return passed
|
||||
}
|
||||
|
||||
@ -38,17 +38,8 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
|
||||
isNameserver = *flags.Nameserver
|
||||
}
|
||||
|
||||
// Feature #72: ntfy-host preference survives upgrades the same way
|
||||
// nameserver does — loaded from preferences.yaml unless the upgrade
|
||||
// flags override it explicitly.
|
||||
isNtfyHost := prefs.NtfyHost
|
||||
if flags.NtfyHost != nil {
|
||||
isNtfyHost = *flags.NtfyHost
|
||||
}
|
||||
|
||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.SkipChecks)
|
||||
setup.SetNameserver(isNameserver)
|
||||
setup.SetNtfyHost(isNtfyHost)
|
||||
|
||||
// Configure Anyone mode (explicit flags > saved preferences > auto-detect)
|
||||
// Explicit flags always win — they represent the user's current intent.
|
||||
@ -220,15 +211,6 @@ func (o *Orchestrator) handleBranchPreferences() error {
|
||||
fmt.Printf(" Nameserver mode: enabled (CoreDNS + Caddy)\n")
|
||||
}
|
||||
|
||||
// If ntfy-host was explicitly provided, persist it (feature #72).
|
||||
if o.flags.NtfyHost != nil {
|
||||
prefs.NtfyHost = *o.flags.NtfyHost
|
||||
prefsChanged = true
|
||||
}
|
||||
if o.setup.IsNtfyHost() {
|
||||
fmt.Printf(" ntfy host: enabled (self-hosted ntfy on push.<dnsZone>)\n")
|
||||
}
|
||||
|
||||
// Anyone client and relay are mutually exclusive — setting one clears the other.
|
||||
if o.flags.AnyoneClient {
|
||||
prefs.AnyoneClient = true
|
||||
|
||||
@ -68,24 +68,16 @@ func (r *RemoteUpgrader) Execute() error {
|
||||
}
|
||||
|
||||
// upgradeNode runs `orama node upgrade --restart` on a single remote node,
|
||||
// forwarding the per-node flags the operator passed locally (--with-ntfy,
|
||||
// --nameserver, --force, --skip-checks) so the remote orchestrator sees the
|
||||
// same intent. Without this forwarding, the remote command would always use
|
||||
// the saved preference, silently dropping operator overrides like
|
||||
// `--with-ntfy` on the floor.
|
||||
// forwarding the per-node flags the operator passed locally (--nameserver,
|
||||
// --force, --skip-checks) so the remote orchestrator sees the same intent.
|
||||
// Without this forwarding, the remote command would always use the saved
|
||||
// preference, silently dropping operator overrides on the floor.
|
||||
func (r *RemoteUpgrader) upgradeNode(node inspector.Node) error {
|
||||
sudo := remotessh.SudoPrefix(node)
|
||||
cmd := fmt.Sprintf("%sorama node upgrade --restart", sudo)
|
||||
|
||||
// Tri-state pointer flags: forward only when explicitly set locally.
|
||||
// Tri-state pointer flag: forward only when explicitly set locally.
|
||||
// nil = "honor saved preference on the remote" — don't pass anything.
|
||||
if r.flags.NtfyHost != nil {
|
||||
if *r.flags.NtfyHost {
|
||||
cmd += " --with-ntfy"
|
||||
} else {
|
||||
cmd += " --with-ntfy=false"
|
||||
}
|
||||
}
|
||||
if r.flags.Nameserver != nil {
|
||||
if *r.flags.Nameserver {
|
||||
cmd += " --nameserver"
|
||||
|
||||
@ -38,7 +38,6 @@ type ProductionSetup struct {
|
||||
skipOptionalDeps bool
|
||||
skipResourceChecks bool
|
||||
isNameserver bool // Whether this node is a nameserver (runs CoreDNS + Caddy)
|
||||
isNtfyHost bool // Feature #72: whether this node hosts the self-hosted ntfy server
|
||||
isAnyoneClient bool // Whether this node runs Anyone as client-only (SOCKS5 proxy)
|
||||
anyoneRelayConfig *AnyoneRelayConfig // Configuration for Anyone relay mode
|
||||
privChecker *PrivilegeChecker
|
||||
@ -136,20 +135,6 @@ func (ps *ProductionSetup) IsNameserver() bool {
|
||||
return ps.isNameserver
|
||||
}
|
||||
|
||||
// SetNtfyHost flags this node as the host for the self-hosted ntfy
|
||||
// server (feature #72). When set, Phase 2 installs ntfy and Phase 4
|
||||
// generates /etc/ntfy/server.yml plus a Caddy reverse-proxy block for
|
||||
// push.<dnsZone>. Requires isNameserver=true for devnet (ns1 also
|
||||
// runs Caddy); production deployments may colocate or split.
|
||||
func (ps *ProductionSetup) SetNtfyHost(isNtfy bool) {
|
||||
ps.isNtfyHost = isNtfy
|
||||
}
|
||||
|
||||
// IsNtfyHost returns whether this node hosts ntfy.
|
||||
func (ps *ProductionSetup) IsNtfyHost() bool {
|
||||
return ps.isNtfyHost
|
||||
}
|
||||
|
||||
// SetAnyoneRelayConfig sets the Anyone relay configuration
|
||||
func (ps *ProductionSetup) SetAnyoneRelayConfig(config *AnyoneRelayConfig) {
|
||||
ps.anyoneRelayConfig = config
|
||||
@ -359,12 +344,14 @@ func (ps *ProductionSetup) installFromSource() error {
|
||||
ps.logf(" ⚠️ Caddy install warning: %v", err)
|
||||
}
|
||||
|
||||
// Install ntfy only on nodes flagged as the ntfy host (feature #72).
|
||||
// On devnet this is ns1; on production it can be a dedicated node.
|
||||
if ps.isNtfyHost {
|
||||
if err := ps.binaryInstaller.InstallNtfy(); err != nil {
|
||||
ps.logf(" ⚠️ ntfy install warning: %v", err)
|
||||
}
|
||||
// Install ntfy on every node (feature #72). ntfy listens on
|
||||
// 127.0.0.1:NtfyListenPort and is only reachable via the local
|
||||
// Caddy reverse-proxy block, so it's safe to run cluster-wide:
|
||||
// nodes that don't host a public push.* DNS entry simply have
|
||||
// an idle ntfy with no inbound traffic. Uniform install means no
|
||||
// per-node toggling and no surprises when DNS topology changes.
|
||||
if err := ps.binaryInstaller.InstallNtfy(); err != nil {
|
||||
ps.logf(" ⚠️ ntfy install warning: %v", err)
|
||||
}
|
||||
|
||||
// These are pre-built binary downloads (not Go compilation), always run them
|
||||
@ -725,20 +712,19 @@ func (ps *ProductionSetup) Phase4GenerateConfigs(peerAddresses []string, vpsIP s
|
||||
email := "admin@" + caddyDomain
|
||||
acmeEndpoint := "http://localhost:6001/v1/internal/acme"
|
||||
|
||||
// Self-hosted ntfy (feature #72): when this node hosts ntfy,
|
||||
// (a) tell the Caddy installer to emit a push.<dnsZone> block
|
||||
// pointing at the local ntfy listen port, and (b) write the
|
||||
// ntfy server.yml. Both must happen BEFORE ConfigureCaddy is
|
||||
// Self-hosted ntfy (feature #72): always emit the Caddy
|
||||
// push.<dnsZone> reverse-proxy block and write
|
||||
// /etc/ntfy/server.yml. Must happen BEFORE ConfigureCaddy is
|
||||
// called below so the generated Caddyfile picks up the block.
|
||||
if ps.isNtfyHost {
|
||||
ntfyHost := "push." + dnsZone
|
||||
ps.binaryInstaller.EnableCaddyNtfyProxy(ntfyHost)
|
||||
ntfyBaseURL := "https://" + ntfyHost
|
||||
if err := ps.binaryInstaller.ConfigureNtfy(ntfyBaseURL); err != nil {
|
||||
ps.logf(" ⚠️ ntfy config warning: %v", err)
|
||||
} else {
|
||||
ps.logf(" ✓ ntfy config generated (base_url: %s)", ntfyBaseURL)
|
||||
}
|
||||
// ntfy is installed unconditionally on every node (see Phase 2)
|
||||
// so the local 127.0.0.1:NtfyListenPort target always exists.
|
||||
ntfyHost := "push." + dnsZone
|
||||
ps.binaryInstaller.EnableCaddyNtfyProxy(ntfyHost)
|
||||
ntfyBaseURL := "https://" + ntfyHost
|
||||
if err := ps.binaryInstaller.ConfigureNtfy(ntfyBaseURL); err != nil {
|
||||
ps.logf(" ⚠️ ntfy config warning: %v", err)
|
||||
} else {
|
||||
ps.logf(" ✓ ntfy config generated (base_url: %s)", ntfyBaseURL)
|
||||
}
|
||||
|
||||
if err := ps.binaryInstaller.ConfigureCaddy(caddyDomain, email, acmeEndpoint, baseDomain); err != nil {
|
||||
@ -899,12 +885,10 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error {
|
||||
if _, err := os.Stat("/usr/bin/caddy"); err == nil {
|
||||
services = append(services, "caddy.service")
|
||||
}
|
||||
// Add ntfy when this node hosts the self-hosted ntfy server (#72).
|
||||
// The unit file is written by installers/ntfy.go::writeSystemdUnit.
|
||||
if ps.isNtfyHost {
|
||||
if _, err := os.Stat("/usr/local/bin/ntfy"); err == nil {
|
||||
services = append(services, "ntfy.service")
|
||||
}
|
||||
// Add ntfy on every node (#72). The unit file is written by
|
||||
// installers/ntfy.go::writeSystemdUnit during Phase 2.
|
||||
if _, err := os.Stat("/usr/local/bin/ntfy"); err == nil {
|
||||
services = append(services, "ntfy.service")
|
||||
}
|
||||
for _, svc := range services {
|
||||
if err := ps.serviceController.EnableService(svc); err != nil {
|
||||
@ -982,16 +966,14 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Start ntfy when this node hosts it (#72). Caddy must already be
|
||||
// up (it terminates TLS for push.<dnsZone>), which the order
|
||||
// above guarantees.
|
||||
if ps.isNtfyHost {
|
||||
if _, err := os.Stat("/usr/local/bin/ntfy"); err == nil {
|
||||
if err := ps.serviceController.RestartService("ntfy.service"); err != nil {
|
||||
ps.logf(" ⚠️ Failed to start ntfy.service: %v", err)
|
||||
} else {
|
||||
ps.logf(" - ntfy.service started")
|
||||
}
|
||||
// Start ntfy on every node (#72). Caddy must already be up (it
|
||||
// terminates TLS for push.<dnsZone>), which the order above
|
||||
// guarantees.
|
||||
if _, err := os.Stat("/usr/local/bin/ntfy"); err == nil {
|
||||
if err := ps.serviceController.RestartService("ntfy.service"); err != nil {
|
||||
ps.logf(" ⚠️ Failed to start ntfy.service: %v", err)
|
||||
} else {
|
||||
ps.logf(" - ntfy.service started")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
type NodePreferences struct {
|
||||
Branch string `yaml:"branch"`
|
||||
Nameserver bool `yaml:"nameserver"`
|
||||
NtfyHost bool `yaml:"ntfy_host"` // Feature #72: this node hosts self-hosted ntfy
|
||||
AnyoneClient bool `yaml:"anyone_client"`
|
||||
AnyoneRelay bool `yaml:"anyone_relay"`
|
||||
AnyoneORPort int `yaml:"anyone_orport,omitempty"` // typically 9001
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@debros/orama",
|
||||
"version": "0.122.15",
|
||||
"version": "0.122.16",
|
||||
"description": "TypeScript SDK for Orama Network - Database, PubSub, Cache, Storage, Vault, and more",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user