Add caddy sync program
This commit is contained in:
348
coolify/proxy/caddy/dynamic/caddy-sync.go
Normal file
348
coolify/proxy/caddy/dynamic/caddy-sync.go
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"git.site.quack-lab.dev/dave/cylogger"
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceConfig struct {
|
||||||
|
Domains []string `toml:"domains"`
|
||||||
|
Backend string `toml:"backend"`
|
||||||
|
IPRange string `toml:"ip_range"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileConfig struct {
|
||||||
|
Services []ServiceConfig `toml:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
IPRanges map[string]string `toml:"ip_ranges"`
|
||||||
|
Files map[string]FileConfig `toml:"files"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template for generating Caddy configuration
|
||||||
|
const caddyTemplate = `{{- range $service := .Services -}}
|
||||||
|
{{ join $service.Domains " " }} {
|
||||||
|
@lan {
|
||||||
|
remote_ip {{ $service.IPRange }}
|
||||||
|
}
|
||||||
|
handle @lan {
|
||||||
|
reverse_proxy {{ $service.Backend }}
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
respond "Njet Molotoff" 403
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ end }}`
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
var (
|
||||||
|
dryRun = flag.Bool("dry-run", false, "Show what would be done without making changes")
|
||||||
|
force = flag.Bool("force", false, "Force apply changes")
|
||||||
|
delete = flag.Bool("d", false, "Delete files not in TOML config")
|
||||||
|
tomlFile = flag.String("config", "services.toml", "Path to TOML configuration file")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
cylogger.InitFlag() // Automatically reads -loglevel flag
|
||||||
|
|
||||||
|
logger := cylogger.Default.WithPrefix(fmt.Sprintf("config=%s", *tomlFile))
|
||||||
|
logger.Info("Starting Caddy configuration sync")
|
||||||
|
logger.Debug("Flags: dry-run=%v, force=%v, delete=%v", *dryRun, *force, *delete)
|
||||||
|
|
||||||
|
if *delete {
|
||||||
|
logger.Warning("Delete mode enabled - will remove files not in TOML")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *dryRun {
|
||||||
|
logger.Info("Dry-run mode enabled - no changes will be made")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse TOML configuration
|
||||||
|
logger.Debug("Loading configuration from TOML")
|
||||||
|
config, err := loadConfig(*tomlFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to load configuration: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
logger.Debug("Successfully loaded configuration")
|
||||||
|
|
||||||
|
// Validate configuration
|
||||||
|
logger.Debug("Validating configuration")
|
||||||
|
if err := validateConfig(config); err != nil {
|
||||||
|
logger.Error("Configuration validation failed: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
logger.Debug("Configuration validation passed")
|
||||||
|
|
||||||
|
// Perform synchronization
|
||||||
|
logger.Debug("Starting synchronization")
|
||||||
|
if err := syncConfigs(config); err != nil {
|
||||||
|
logger.Error("Synchronization failed: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Caddy configuration sync completed successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(filename string) (*Config, error) {
|
||||||
|
logger := cylogger.Default.WithPrefix(fmt.Sprintf("file=%s", filename))
|
||||||
|
logger.Debug("Loading TOML configuration")
|
||||||
|
|
||||||
|
var config Config
|
||||||
|
|
||||||
|
_, err := toml.DecodeFile(filename, &config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode TOML: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Trace("Loaded %d IP ranges and %d files", len(config.IPRanges), len(config.Files))
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateConfig(config *Config) error {
|
||||||
|
// Validate IP ranges are defined
|
||||||
|
for filename, fileConfig := range config.Files {
|
||||||
|
for i, service := range fileConfig.Services {
|
||||||
|
if service.IPRange == "" {
|
||||||
|
return fmt.Errorf("service %d in file %s has no IP range specified", i+1, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := config.IPRanges[service.IPRange]; !exists {
|
||||||
|
return fmt.Errorf("IP range '%s' not defined for service %d in file %s", service.IPRange, i+1, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(service.Domains) == 0 {
|
||||||
|
return fmt.Errorf("service %d in file %s has no domains specified", i+1, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.Backend == "" {
|
||||||
|
return fmt.Errorf("service %d in file %s has no backend specified", i+1, filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncConfigs(config *Config) error {
|
||||||
|
// Get current directory
|
||||||
|
currentDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get current directory: %w", err)
|
||||||
|
}
|
||||||
|
logger := cylogger.Default.WithPrefix(fmt.Sprintf("dir=%s", currentDir))
|
||||||
|
|
||||||
|
// Get existing .caddy files
|
||||||
|
logger.Debug("Scanning for existing .caddy files")
|
||||||
|
existingFiles, err := getExistingCaddyFiles(currentDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get existing .caddy files: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debug("Found %d existing .caddy files", len(existingFiles))
|
||||||
|
|
||||||
|
// Track which files we've processed
|
||||||
|
processedFiles := make(map[string]bool)
|
||||||
|
var created, updated, unchanged int
|
||||||
|
|
||||||
|
// Process each file in configuration
|
||||||
|
logger.Debug("Processing %d configured files", len(config.Files))
|
||||||
|
for filename, fileConfig := range config.Files {
|
||||||
|
caddyFilename := filename + ".caddy"
|
||||||
|
processedFiles[caddyFilename] = true
|
||||||
|
fileLogger := logger.WithPrefix(fmt.Sprintf("file=%s", caddyFilename))
|
||||||
|
fileLogger.Trace("Processing")
|
||||||
|
|
||||||
|
// Generate expected content
|
||||||
|
expectedContent, err := generateCaddyContent(fileConfig, config.IPRanges)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate content for %s: %w", caddyFilename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file exists and compare content
|
||||||
|
existingContent, exists := existingFiles[caddyFilename]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
// File doesn't exist, create it
|
||||||
|
fileLogger.Info("Creating new file")
|
||||||
|
created++
|
||||||
|
if !*dryRun {
|
||||||
|
if err := writeFile(caddyFilename, expectedContent); err != nil {
|
||||||
|
return fmt.Errorf("failed to create file %s: %w", caddyFilename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if normalizeContent(existingContent) != normalizeContent(expectedContent) {
|
||||||
|
// File exists but content differs
|
||||||
|
fileLogger.Warning("File content differs, updating")
|
||||||
|
updated++
|
||||||
|
|
||||||
|
// Show detailed diff of what's changing
|
||||||
|
generateAndLogDiff(fileLogger, caddyFilename, existingContent, expectedContent)
|
||||||
|
|
||||||
|
if !*dryRun {
|
||||||
|
if err := writeFile(caddyFilename, expectedContent); err != nil {
|
||||||
|
return fmt.Errorf("failed to update file %s: %w", caddyFilename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// File exists and content matches
|
||||||
|
fileLogger.Debug("File content matches, no action needed")
|
||||||
|
unchanged++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle orphaned files (files that exist but are not in config)
|
||||||
|
var orphanedCount int
|
||||||
|
for filename := range existingFiles {
|
||||||
|
if !processedFiles[filename] {
|
||||||
|
orphanedCount++
|
||||||
|
orphanLogger := logger.WithPrefix(fmt.Sprintf("orphan=%s", filename))
|
||||||
|
if *delete {
|
||||||
|
orphanLogger.Warning("Deleting orphaned file")
|
||||||
|
if !*dryRun {
|
||||||
|
if err := os.Remove(filename); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete file %s: %w", filename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
orphanLogger.Warning("Found orphaned file not in configuration (use -d to delete)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Sync summary: created=%d, updated=%d, unchanged=%d, orphaned=%d",
|
||||||
|
created, updated, unchanged, orphanedCount)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCaddyContent(fileConfig FileConfig, ipRanges map[string]string) (string, error) {
|
||||||
|
logger := cylogger.Default.WithPrefix(fmt.Sprintf("template services=%d", len(fileConfig.Services)))
|
||||||
|
logger.Debug("Generating Caddy content")
|
||||||
|
|
||||||
|
// Create template data with resolved IP ranges
|
||||||
|
templateData := struct {
|
||||||
|
Services []ServiceConfig
|
||||||
|
}{
|
||||||
|
Services: make([]ServiceConfig, len(fileConfig.Services)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve IP ranges for each service
|
||||||
|
for i, service := range fileConfig.Services {
|
||||||
|
logger.Trace("Resolving service %d: domains=%v, backend=%s, ip_range=%s",
|
||||||
|
i, service.Domains, service.Backend, service.IPRange)
|
||||||
|
|
||||||
|
templateData.Services[i] = ServiceConfig{
|
||||||
|
Domains: service.Domains,
|
||||||
|
Backend: service.Backend,
|
||||||
|
IPRange: ipRanges[service.IPRange],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create template with join function
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
"join": strings.Join,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("caddy").Funcs(funcMap).Parse(caddyTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to parse template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result strings.Builder
|
||||||
|
if err := tmpl.Execute(&result, templateData); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := result.String()
|
||||||
|
logger.Trace("Generated content:\n%s", content)
|
||||||
|
return content, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExistingCaddyFiles(dir string) (map[string]string, error) {
|
||||||
|
logger := cylogger.Default.WithPrefix(fmt.Sprintf("scanner dir=%s", dir))
|
||||||
|
logger.Debug("Scanning directory for .caddy files")
|
||||||
|
|
||||||
|
files := make(map[string]string)
|
||||||
|
|
||||||
|
entries, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".caddy") {
|
||||||
|
// Skip services.toml and other non-caddy files
|
||||||
|
if entry.Name() == "services.toml" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Trace("Found .caddy file: %s", entry.Name())
|
||||||
|
content, err := os.ReadFile(filepath.Join(dir, entry.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read file %s: %w", entry.Name(), err)
|
||||||
|
}
|
||||||
|
files[entry.Name()] = string(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Scanned %d files, found %d .caddy files", len(entries), len(files))
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFile(filename, content string) error {
|
||||||
|
return os.WriteFile(filename, []byte(content), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAndLogDiff(logger *cylogger.Logger, filename, existingContent, expectedContent string) {
|
||||||
|
logger.Info("Changes needed for %s:", filename)
|
||||||
|
|
||||||
|
// ANSI color codes
|
||||||
|
const (
|
||||||
|
ColorRed = "\033[31m"
|
||||||
|
ColorGreen = "\033[32m"
|
||||||
|
ColorReset = "\033[0m"
|
||||||
|
)
|
||||||
|
|
||||||
|
dmp := diffmatchpatch.New()
|
||||||
|
diffs := dmp.DiffMain(existingContent, expectedContent, false)
|
||||||
|
|
||||||
|
// Use the library's built-in pretty diff formatting
|
||||||
|
prettyDiff := dmp.DiffPrettyText(diffs)
|
||||||
|
|
||||||
|
// Print the pretty diff with colors
|
||||||
|
lines := strings.Split(prettyDiff, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(line, "+") {
|
||||||
|
fmt.Printf("%s%s%s\n", ColorGreen, line, ColorReset)
|
||||||
|
} else if strings.HasPrefix(line, "-") {
|
||||||
|
fmt.Printf("%s%s%s\n", ColorRed, line, ColorReset)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s\n", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeContent(content string) string {
|
||||||
|
// Normalize content for comparison by trimming whitespace and standardizing line endings
|
||||||
|
lines := strings.Split(content, "\n")
|
||||||
|
var normalizedLines []string
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
normalizedLines = append(normalizedLines, strings.TrimSpace(line))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(normalizedLines, "\n")
|
||||||
|
}
|
||||||
20
coolify/proxy/caddy/dynamic/go.mod
Normal file
20
coolify/proxy/caddy/dynamic/go.mod
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
module caddy-sync
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
toolchain go1.23.6
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.site.quack-lab.dev/dave/cylogger v1.5.0
|
||||||
|
github.com/BurntSushi/toml v1.3.2
|
||||||
|
github.com/sergi/go-diff v1.4.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
github.com/hexops/valast v1.5.0 // indirect
|
||||||
|
golang.org/x/mod v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.3.0 // indirect
|
||||||
|
golang.org/x/tools v0.4.0 // indirect
|
||||||
|
mvdan.cc/gofumpt v0.4.0 // indirect
|
||||||
|
)
|
||||||
48
coolify/proxy/caddy/dynamic/go.sum
Normal file
48
coolify/proxy/caddy/dynamic/go.sum
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
git.site.quack-lab.dev/dave/cylogger v1.5.0 h1:9H/eEMD1dqJ9hEudwbszxrzE9lN0P0iCeYOzYRPMWOA=
|
||||||
|
git.site.quack-lab.dev/dave/cylogger v1.5.0/go.mod h1:wctgZplMvroA4X6p8f4B/LaCKtiBcT1Pp+L14kcS8jk=
|
||||||
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||||
|
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/hexops/autogold v0.8.1 h1:wvyd/bAJ+Dy+DcE09BoLk6r4Fa5R5W+O+GUzmR985WM=
|
||||||
|
github.com/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY=
|
||||||
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
|
github.com/hexops/valast v1.5.0 h1:FBTuvVi0wjTngtXJRZXMbkN/Dn6DgsUsBwch2DUJU8Y=
|
||||||
|
github.com/hexops/valast v1.5.0/go.mod h1:Jcy1pNH7LNraVaAZDLyv21hHg2WBv9Nf9FL6fGxU7o4=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||||
|
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||||
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
|
||||||
|
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
|
||||||
|
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
||||||
61
coolify/proxy/caddy/dynamic/services.toml
Normal file
61
coolify/proxy/caddy/dynamic/services.toml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# IP ranges that can be referenced by name
|
||||||
|
[ip_ranges]
|
||||||
|
lan = "192.168.0.0/16 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12"
|
||||||
|
|
||||||
|
# Caddy configuration files - each key creates a separate .caddy file
|
||||||
|
[files.actual]
|
||||||
|
services = [
|
||||||
|
{ domains = ["actual.site.quack-lab.dev"], backend = "actual_server:5006", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.meilisearch]
|
||||||
|
services = [
|
||||||
|
{ domains = ["meili.site.quack-lab.dev"], backend = "meilisearch:7700", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.meili-web]
|
||||||
|
services = [
|
||||||
|
{ domains = ["meili-web.site.quack-lab.dev"], backend = "meili-web:24900", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.grist]
|
||||||
|
services = [
|
||||||
|
{ domains = ["grist.site.quack-lab.dev"], backend = "grist:8484", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.nsq]
|
||||||
|
services = [
|
||||||
|
{ domains = ["nsq.site.quack-lab.dev", "nsq-http.site.quack-lab.dev"], backend = "nsqd:4151", ip_range = "lan" },
|
||||||
|
{ domains = ["nsqadmin.site.quack-lab.dev"], backend = "nsqadmin:4171", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.monitoring]
|
||||||
|
services = [
|
||||||
|
{ domains = ["prometheus.site.quack-lab.dev", "vmagent.site.quack-lab.dev"], backend = "host.docker.internal:43261", ip_range = "lan" },
|
||||||
|
{ domains = ["victoria.site.quack-lab.dev"], backend = "host.docker.internal:8428", ip_range = "lan" },
|
||||||
|
{ domains = ["grafana.site.quack-lab.dev"], backend = "grafana-jococcw004848ck4k0owwww0:43433", ip_range = "lan" },
|
||||||
|
{ domains = ["nodeexporter-sparky.site.quack-lab.dev"], backend = "host.docker.internal:56546", ip_range = "lan" },
|
||||||
|
{ domains = ["libre-metrics-exporter-dave.site.quack-lab.dev"], backend = "192.168.1.64:9646", ip_range = "lan" },
|
||||||
|
{ domains = ["libre-metrics-exporter-jana.site.quack-lab.dev"], backend = "192.168.1.68:9646", ip_range = "lan" },
|
||||||
|
{ domains = ["power-meter-reader.site.quack-lab.dev"], backend = "host.docker.internal:9646", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.pdf]
|
||||||
|
services = [
|
||||||
|
{ domains = ["pdf.site.quack-lab.dev"], backend = "stirling-pdf:8080", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.torrent]
|
||||||
|
services = [
|
||||||
|
{ domains = ["torrent.site.quack-lab.dev"], backend = "qbit:8080", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.portainer]
|
||||||
|
services = [
|
||||||
|
{ domains = ["portainer.site.quack-lab.dev"], backend = "portainer:9000", ip_range = "lan" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[files.webtop]
|
||||||
|
services = [
|
||||||
|
{ domains = ["webtop.site.quack-lab.dev"], backend = "webtop:3000", ip_range = "lan" }
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user