Skip to content

Commit ae6ed0a

Browse files
committed
feat(nginx): sync missing configs on startup and surface write errors
- Add SyncConfigs() to recreate nginx configs for enabled domains missing on disk, called on every service startup - Return writeAndReload error from Create instead of swallowing it - Handle partial success in create handler (domain saved, config failed)
1 parent 705e322 commit ae6ed0a

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

cmd/server/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ func main() {
7575
slog.Error("failed to sync nftables rules on startup", "error", err)
7676
}
7777

78+
// Sync nginx configs on startup
79+
if err := nginxSvc.SyncConfigs(); err != nil {
80+
slog.Error("failed to sync nginx configs on startup", "error", err)
81+
}
82+
7883
// Handlers
7984
authHandler := auth.NewHandler(authSvc)
8085
natHandler := nftables.NewHandler(natSvc)

internal/nginx/handler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package nginx
22

33
import (
4+
"log/slog"
45
"net/http"
56
"strconv"
67

@@ -47,10 +48,13 @@ func (h *Handler) create(w http.ResponseWriter, r *http.Request) {
4748
}
4849

4950
domain, err := h.svc.Create(req)
50-
if err != nil {
51+
if err != nil && domain == nil {
5152
httputil.Error(w, http.StatusBadRequest, err.Error())
5253
return
5354
}
55+
if err != nil {
56+
slog.Warn("domain created with config error", "error", err, "domain", domain.Domain)
57+
}
5458
httputil.JSON(w, http.StatusCreated, domain)
5559
}
5660

internal/nginx/service.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,33 @@ func (s *Service) GetAll() ([]Domain, error) {
2828
return s.repo.GetAll()
2929
}
3030

31+
// SyncConfigs writes nginx configs for all enabled domains that are missing on disk.
32+
func (s *Service) SyncConfigs() error {
33+
if runtime.GOOS != "linux" {
34+
return nil
35+
}
36+
37+
domains, err := s.repo.GetAll()
38+
if err != nil {
39+
return fmt.Errorf("get domains: %w", err)
40+
}
41+
42+
for _, d := range domains {
43+
if !d.Enabled {
44+
continue
45+
}
46+
path := s.configPath(d.Domain)
47+
if _, err := os.Stat(path); err == nil {
48+
continue // config already exists
49+
}
50+
slog.Info("syncing missing nginx config", "domain", d.Domain)
51+
if err := s.writeAndReload(&d); err != nil {
52+
slog.Error("failed to sync nginx config", "error", err, "domain", d.Domain)
53+
}
54+
}
55+
return nil
56+
}
57+
3158
func (s *Service) Create(req CreateDomainRequest) (*Domain, error) {
3259
if err := validate.Domain(req.Domain); err != nil {
3360
return nil, err
@@ -74,7 +101,7 @@ func (s *Service) Create(req CreateDomainRequest) (*Domain, error) {
74101
}
75102

76103
if err := s.writeAndReload(domain); err != nil {
77-
slog.Error("failed to write nginx config", "error", err, "domain", domain.Domain)
104+
return domain, fmt.Errorf("domain created but nginx config failed: %w", err)
78105
}
79106

80107
return domain, nil

0 commit comments

Comments
 (0)