Add the Blacktip edge

The edge: per-IP TCP/UDP/HTTP/HTTPS/TLS listeners with port ranges and PROXY
protocol, WireGuard tunnel endpoint, logins in front of web ports (built-in
proxy or Traefik), health checks and failover, and mail egress with DKIM
signing and MTA-STS. Split out of the original single repository; depends on
Reef for the shared types.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
VeillaxandClaude Sonnet 5.5 committed 2026-10-26 02:45:16 -06:00
1 parent 995ef9a6aa
commit 9448a532e9
17 files changed
+3492 -1

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
// Blacktip is the edge: run it on a public server that owns the IP addresses.
package main
import (
"context"
"flag"
"log"
"os"
"os/signal"
"strings"
"git.veillax.com/Veillax/blacktip"
"git.veillax.com/Veillax/reef/dotenv"
)
func env(k, def string) string {
if v := os.Getenv(k); v != "" {
return v
}
return def
}
func main() {
// secrets (tokens, DNS-provider credentials) can live in a .env file instead of the command line
envFile := dotenv.ArgPath(os.Args[1:], ".env")
if _, err := dotenv.Load(envFile); err != nil {
log.Fatalf("read %s: %v", envFile, err)
}
hh := flag.String("hammerhead", env("BLACKTIP_HAMMERHEAD", ""), "URL of hammerhead, e.g. http://10.0.0.5:8080")
token := flag.String("token", env("BLACKTIP_TOKEN", ""), "edge token from the hammerhead UI")
tun := flag.String("tunnel", env("BLACKTIP_TUNNEL", ":51820"), "UDP listen address for the WireGuard tunnel (open this UDP port in your firewall)")
data := flag.String("data", env("BLACKTIP_DATA", "./blacktip-data"), "directory for the WireGuard key and certificates")
dockerOn := flag.Bool("docker", os.Getenv("BLACKTIP_DOCKER") == "1", "report local Docker containers so they can be picked as targets in the UI")
traefikPath := flag.String("traefik", os.Getenv("BLACKTIP_TRAEFIK"), "path to a Traefik binary: serve http/https resources with Traefik instead of the built-in proxy")
acmeDNS := flag.String("acme-dns", os.Getenv("BLACKTIP_ACME_DNS"), "with -traefik: DNS-challenge provider (e.g. cloudflare) for wildcard certificates; its credentials go in this process's environment")
noACME := flag.Bool("no-acme", false, "with -traefik: serve Traefik's self-signed certificate instead of requesting Let's Encrypt ones")
flag.String("env", ".env", "file to read secrets and settings from")
flag.Parse()
if *hh == "" || *token == "" {
flag.Usage()
os.Exit(2)
}
b, err := blacktip.New(blacktip.Config{
Hammerhead: strings.TrimRight(*hh, "/"), Token: *token, TunnelAddr: *tun, DataDir: *data, Docker: *dockerOn,
Traefik: blacktip.TraefikConfig{Path: *traefikPath, ACMEDNS: *acmeDNS, NoACME: *noACME},
})
if err != nil {
log.Fatal(err)
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
if err := b.Run(ctx); err != nil {
log.Fatal(err)
}
}