Rename wild-cloud → wild-central for all managed config files and nftables table

Completes the naming separation: nftables table, rules file, dnsmasq config,
resolved config, systemd unit, sudoers rule, and temp files now all use
the wild-central name.
This commit is contained in:
2026-07-14 15:31:50 +00:00
parent 282d255c0a
commit 245d260a2b
10 changed files with 61 additions and 61 deletions

View File

@@ -28,16 +28,16 @@ case "$1" in
chgrp wildcloud /etc/dnsmasq.d
chmod 775 /etc/dnsmasq.d
# Create or fix ownership of wild-cloud.conf
if [ ! -f /etc/dnsmasq.d/wild-cloud.conf ]; then
touch /etc/dnsmasq.d/wild-cloud.conf
echo "Created /etc/dnsmasq.d/wild-cloud.conf"
# Create or fix ownership of wild-central.conf
if [ ! -f /etc/dnsmasq.d/wild-central.conf ]; then
touch /etc/dnsmasq.d/wild-central.conf
echo "Created /etc/dnsmasq.d/wild-central.conf"
else
echo "Found existing /etc/dnsmasq.d/wild-cloud.conf - updating ownership"
echo "Found existing /etc/dnsmasq.d/wild-central.conf - updating ownership"
fi
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-cloud.conf
chmod 644 /etc/dnsmasq.d/wild-cloud.conf
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-central.conf
chmod 644 /etc/dnsmasq.d/wild-central.conf
# Set ownership and permissions for instance configs directory
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-cloud-instances
@@ -47,14 +47,14 @@ case "$1" in
# Set up systemd-resolved configuration directory and file
mkdir -p /etc/systemd/resolved.conf.d
if [ ! -f /etc/systemd/resolved.conf.d/wild-cloud.conf ]; then
touch /etc/systemd/resolved.conf.d/wild-cloud.conf
echo "Created /etc/systemd/resolved.conf.d/wild-cloud.conf"
if [ ! -f /etc/systemd/resolved.conf.d/wild-central.conf ]; then
touch /etc/systemd/resolved.conf.d/wild-central.conf
echo "Created /etc/systemd/resolved.conf.d/wild-central.conf"
else
echo "Found existing /etc/systemd/resolved.conf.d/wild-cloud.conf"
echo "Found existing /etc/systemd/resolved.conf.d/wild-central.conf"
fi
chown wildcloud:wildcloud /etc/systemd/resolved.conf.d/wild-cloud.conf
chmod 644 /etc/systemd/resolved.conf.d/wild-cloud.conf
chown wildcloud:wildcloud /etc/systemd/resolved.conf.d/wild-central.conf
chmod 644 /etc/systemd/resolved.conf.d/wild-central.conf
# Ensure /etc/resolv.conf is a symlink to systemd-resolved stub
# Skip in Docker/container environments where resolv.conf might be bind-mounted
@@ -101,16 +101,16 @@ case "$1" in
# Set up nftables configuration directory
mkdir -p /etc/nftables.d
if [ ! -f /etc/nftables.d/wild-cloud.nft ]; then
touch /etc/nftables.d/wild-cloud.nft
echo "Created /etc/nftables.d/wild-cloud.nft"
if [ ! -f /etc/nftables.d/wild-central.nft ]; then
touch /etc/nftables.d/wild-central.nft
echo "Created /etc/nftables.d/wild-central.nft"
fi
chown wildcloud:wildcloud /etc/nftables.d/wild-cloud.nft
chmod 644 /etc/nftables.d/wild-cloud.nft
chown wildcloud:wildcloud /etc/nftables.d/wild-central.nft
chmod 644 /etc/nftables.d/wild-central.nft
# Ensure nftables.conf includes wild-cloud rules
if [ -f /etc/nftables.conf ] && ! grep -q 'wild-cloud.nft' /etc/nftables.conf; then
echo 'include "/etc/nftables.d/wild-cloud.nft"' >> /etc/nftables.conf
# Ensure nftables.conf includes wild-central rules
if [ -f /etc/nftables.conf ] && ! grep -q 'wild-central.nft' /etc/nftables.conf; then
echo 'include "/etc/nftables.d/wild-central.nft"' >> /etc/nftables.conf
echo "Added Wild Central nftables include to /etc/nftables.conf"
fi
echo "Configured nftables for Wild Central management"
@@ -192,7 +192,7 @@ AUTHELIA_EOF
# Install sudoers rules for privileged operations
cat > /etc/sudoers.d/wild-central << 'SUDOERS_EOF'
wildcloud ALL=(ALL) NOPASSWD: /usr/sbin/nft -c -f *, /usr/sbin/nft list table inet wild-cloud, /usr/bin/cscli bouncers *, /usr/bin/cscli machines *, /usr/bin/cscli decisions *, /usr/bin/cscli alerts *, /usr/bin/cscli version, /usr/bin/wg-quick up wg0, /usr/bin/wg-quick down wg0, /usr/bin/wg show wg0, /usr/bin/certbot *, /usr/sbin/nginx -t, /usr/bin/systemctl reload nginx
wildcloud ALL=(ALL) NOPASSWD: /usr/sbin/nft -c -f *, /usr/sbin/nft list table inet wild-central, /usr/bin/cscli bouncers *, /usr/bin/cscli machines *, /usr/bin/cscli decisions *, /usr/bin/cscli alerts *, /usr/bin/cscli version, /usr/bin/wg-quick up wg0, /usr/bin/wg-quick down wg0, /usr/bin/wg show wg0, /usr/bin/certbot *, /usr/sbin/nginx -t, /usr/bin/systemctl reload nginx
SUDOERS_EOF
chmod 440 /etc/sudoers.d/wild-central
echo "Installed sudoers rules for Wild Central"

View File

@@ -18,14 +18,14 @@ case "$1" in
fi
# Remove dnsmasq configuration
if [ -f /etc/dnsmasq.d/wild-cloud.conf ]; then
rm -f /etc/dnsmasq.d/wild-cloud.conf
if [ -f /etc/dnsmasq.d/wild-central.conf ]; then
rm -f /etc/dnsmasq.d/wild-central.conf
echo "Removed dnsmasq configuration"
fi
# Remove systemd-resolved configuration
if [ -f /etc/systemd/resolved.conf.d/wild-cloud.conf ]; then
rm -f /etc/systemd/resolved.conf.d/wild-cloud.conf
if [ -f /etc/systemd/resolved.conf.d/wild-central.conf ]; then
rm -f /etc/systemd/resolved.conf.d/wild-central.conf
echo "Removed systemd-resolved configuration"
systemctl restart systemd-resolved 2>/dev/null || true
fi

View File

@@ -5,5 +5,5 @@ After=network.target nftables.service
[Service]
Type=oneshot
ExecStart=/usr/sbin/nft -f /etc/nftables.d/wild-cloud.nft
ExecStart=/usr/sbin/nft -f /etc/nftables.d/wild-central.nft
RemainAfterExit=no

View File

@@ -60,9 +60,9 @@ type API struct {
// NewAPI creates a new Central API handler with all dependencies
func NewAPI(dataDir, version string, allowedOrigins []string) (*API, error) {
// Determine config paths from env or defaults
dnsmasqConfigPath := envOrDefault("WILD_CENTRAL_DNSMASQ_CONFIG_PATH", "/etc/dnsmasq.d/wild-cloud.conf")
dnsmasqConfigPath := envOrDefault("WILD_CENTRAL_DNSMASQ_CONFIG_PATH", "/etc/dnsmasq.d/wild-central.conf")
haproxyConfigPath := envOrDefault("WILD_CENTRAL_HAPROXY_CONFIG_PATH", "/etc/haproxy/haproxy.cfg")
nftablesRulesPath := envOrDefault("WILD_CENTRAL_NFTABLES_RULES_PATH", "/etc/nftables.d/wild-cloud.nft")
nftablesRulesPath := envOrDefault("WILD_CENTRAL_NFTABLES_RULES_PATH", "/etc/nftables.d/wild-central.nft")
vpnConfigPath := envOrDefault("WILD_CENTRAL_VPN_CONFIG_PATH", "/etc/wireguard/wg0.conf")
sseManager := sse.NewManager()
@@ -540,8 +540,8 @@ func getDaemonStatus() map[string]map[string]any {
result[name] = entry
}
// nftables has no persistent service — check if the wild-cloud table exists
nftErr := exec.Command("sudo", "nft", "list", "table", "inet", "wild-cloud").Run()
// nftables has no persistent service — check if the wild-central table exists
nftErr := exec.Command("sudo", "nft", "list", "table", "inet", "wild-central").Run()
nftEntry := map[string]any{"active": nftErr == nil}
if out, verErr := exec.Command("nft", "--version").Output(); verErr == nil {
// "nftables v1.0.9 (Old Doc Yak #3)"

View File

@@ -10,7 +10,7 @@ import (
"github.com/wild-cloud/wild-central/internal/haproxy"
)
// NftablesStatus returns the current wild-cloud nftables table contents
// NftablesStatus returns the current wild-central nftables table contents
func (api *API) NftablesStatus(w http.ResponseWriter, r *http.Request) {
rules, err := api.nftables.GetStatus()
if err != nil {
@@ -56,7 +56,7 @@ func (api *API) vpnAutoUDPPorts() []int {
func (api *API) syncNftablesOnly(globalCfg *config.State) {
nftCfg := globalCfg.Cloud.Nftables
// Explicitly disabled: flush the wild-cloud table
// Explicitly disabled: flush the wild-central table
if nftCfg.Enabled != nil && !*nftCfg.Enabled {
if err := api.nftables.WriteDisabledRules(); err != nil {
slog.Error("failed to write disabled nftables rules", "component", "nftables-sync", "error", err)

View File

@@ -22,7 +22,7 @@ func setupTestNftables(t *testing.T) (*API, string) {
}
// TestNftablesStatus_ReturnsOK verifies the status endpoint returns 200.
// GetStatus() runs `nft list table inet wild-cloud` and silently returns an
// GetStatus() runs `nft list table inet wild-central` and silently returns an
// empty string if nft is not installed or the table doesn't exist, so this
// endpoint always returns 200.
func TestNftablesStatus_ReturnsOK(t *testing.T) {
@@ -109,7 +109,7 @@ func TestNftablesApply_ServiceUnavailable(t *testing.T) {
api.NftablesApply(w, req)
// ApplyRules calls `systemctl start wild-cloud-nftables-reload.service`
// ApplyRules calls `systemctl start wild-central-nftables-reload.service`
// which requires polkit/root — always fails in test environments.
if w.Code != http.StatusInternalServerError {
// If it happened to succeed (running on the actual Wild Central device

View File

@@ -34,7 +34,7 @@ type Manager struct {
// NewManager creates a new dnsmasq config generator
func NewManager(configPath string) *Manager {
if configPath == "" {
configPath = "/etc/dnsmasq.d/wild-cloud.conf"
configPath = "/etc/dnsmasq.d/wild-central.conf"
}
return &Manager{
configPath: configPath,
@@ -388,7 +388,7 @@ func (g *Manager) ConfigureSystemDNS() error {
// Write systemd-resolved configuration to file owned by wildcloud user
// (created during package installation in postinst)
resolvedConfPath := "/etc/systemd/resolved.conf.d/wild-cloud.conf"
resolvedConfPath := "/etc/systemd/resolved.conf.d/wild-central.conf"
resolvedConf := fmt.Sprintf("[Resolve]\nDNS=%s\nDomains=~.\n", dnsIP)
if err := os.WriteFile(resolvedConfPath, []byte(resolvedConf), 0644); err != nil {

View File

@@ -191,8 +191,8 @@ func TestNewManager_CustomPath(t *testing.T) {
// Test: NewManager uses default path when empty
func TestNewManager_DefaultPath(t *testing.T) {
g := NewManager("")
if g.GetConfigPath() != "/etc/dnsmasq.d/wild-cloud.conf" {
t.Errorf("got %q, want /etc/dnsmasq.d/wild-cloud.conf", g.GetConfigPath())
if g.GetConfigPath() != "/etc/dnsmasq.d/wild-central.conf" {
t.Errorf("got %q, want /etc/dnsmasq.d/wild-central.conf", g.GetConfigPath())
}
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/wild-cloud/wild-central/internal/storage"
)
const defaultRulesPath = "/etc/nftables.d/wild-cloud.nft"
const defaultRulesPath = "/etc/nftables.d/wild-central.nft"
// Manager handles nftables rule generation and application
type Manager struct {
@@ -68,15 +68,15 @@ func (m *Manager) Generate(haproxyPorts []int, extraTCPPorts []int, extraUDPPort
var sb strings.Builder
sb.WriteString("# Wild Cloud nftables rules\n")
sb.WriteString("# Managed by Wild Cloud Central API — do not edit manually\n\n")
sb.WriteString("# Wild Central nftables rules\n")
sb.WriteString("# Managed by Wild Central — do not edit manually\n\n")
// Delete and recreate the table so re-applying never accumulates stale set elements.
// The first line ensures the table exists (so delete never errors on first run).
sb.WriteString("table inet wild-cloud {}\n")
sb.WriteString("delete table inet wild-cloud\n\n")
sb.WriteString("table inet wild-central {}\n")
sb.WriteString("delete table inet wild-central\n\n")
sb.WriteString("table inet wild-cloud {\n")
sb.WriteString("table inet wild-central {\n")
sb.WriteString(" # TCP ports allowed through the firewall (HAProxy + extra TCP)\n")
sb.WriteString(" set allowed_tcp_ports {\n")
sb.WriteString(" type inet_service\n")
@@ -148,7 +148,7 @@ func ValidateWANInterface(name string) error {
// On apply failure, rolls back to the previous rules.
func (m *Manager) SafeApply(content string) error {
// Validate syntax
tmpFile := "/tmp/wild-cloud-nft-safeapply.tmp"
tmpFile := "/tmp/wild-central-nft-safeapply.tmp"
if err := os.WriteFile(tmpFile, []byte(content), 0644); err != nil {
return fmt.Errorf("writing validation file: %w", err)
}
@@ -204,7 +204,7 @@ func (m *Manager) verify() error {
// Validation uses a temp file in /tmp (world-writable) to avoid needing
// write permission on the /etc/nftables.d/ directory itself.
func (m *Manager) WriteRules(content string) error {
tempFile := "/tmp/wild-cloud-nft-validate.tmp"
tempFile := "/tmp/wild-central-nft-validate.tmp"
if err := os.WriteFile(tempFile, []byte(content), 0644); err != nil {
return fmt.Errorf("writing temp rules: %w", err)
@@ -224,9 +224,9 @@ func (m *Manager) WriteRules(content string) error {
}
// ApplyRules loads the rules file into the kernel via a systemd oneshot service.
// The wildcloud user has polkit permission to start wild-cloud-nftables-reload.service.
// The wildcloud user has polkit permission to start wild-central-nftables-reload.service.
func (m *Manager) ApplyRules() error {
cmd := exec.Command("systemctl", "start", "wild-cloud-nftables-reload.service")
cmd := exec.Command("systemctl", "start", "wild-central-nftables-reload.service")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("applying nftables rules: %w (output: %s)", err, string(output))
@@ -235,13 +235,13 @@ func (m *Manager) ApplyRules() error {
return nil
}
// WriteDisabledRules writes a rules file that flushes the wild-cloud table,
// removing all Wild Cloud firewall rules from the kernel when applied.
// WriteDisabledRules writes a rules file that flushes the wild-central table,
// removing all Wild Central firewall rules from the kernel when applied.
func (m *Manager) WriteDisabledRules() error {
content := "# Wild Cloud nftables rules — firewall disabled\n" +
"# Managed by Wild Cloud Central API — do not edit manually\n\n" +
"table inet wild-cloud {}\n" +
"delete table inet wild-cloud\n"
content := "# Wild Central nftables rules — firewall disabled\n" +
"# Managed by Wild Central — do not edit manually\n\n" +
"table inet wild-central {}\n" +
"delete table inet wild-central\n"
if err := storage.WriteFileAtomic(m.rulesPath, []byte(content), 0644); err != nil {
return fmt.Errorf("writing disabled rules file: %w", err)
}
@@ -249,10 +249,10 @@ func (m *Manager) WriteDisabledRules() error {
return nil
}
// GetStatus returns the current wild-cloud nftables table as a string.
// GetStatus returns the current wild-central nftables table as a string.
// Uses sudo to allow the wildcloud user to read kernel state.
func (m *Manager) GetStatus() (string, error) {
cmd := exec.Command("sudo", "nft", "list", "table", "inet", "wild-cloud")
cmd := exec.Command("sudo", "nft", "list", "table", "inet", "wild-central")
output, err := cmd.CombinedOutput()
if err != nil {
// Table may not exist yet — not an error

View File

@@ -13,9 +13,9 @@ func TestNewManager_DefaultPath(t *testing.T) {
}
func TestNewManager_CustomPath(t *testing.T) {
m := NewManager("/tmp/wild-cloud.nft")
if m.GetRulesPath() != "/tmp/wild-cloud.nft" {
t.Errorf("got %q, want /tmp/wild-cloud.nft", m.GetRulesPath())
m := NewManager("/tmp/wild-central.nft")
if m.GetRulesPath() != "/tmp/wild-central.nft" {
t.Errorf("got %q, want /tmp/wild-central.nft", m.GetRulesPath())
}
}
@@ -40,7 +40,7 @@ func TestGenerate_AlwaysIncludesStructure(t *testing.T) {
out := m.Generate([]int{80, 443}, nil, nil, "")
for _, want := range []string{
"table inet wild-cloud",
"table inet wild-central",
"set allowed_tcp_ports",
"chain input",
"type filter hook input priority filter; policy accept;",