mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-11 09:18:50 +00:00
feat: add domain configuration and ACME TLS support for gateway
- Introduced a new `Domain` field in the gateway configuration to support HTTPS and ACME certificate provisioning. - Implemented domain validation to ensure proper format. - Enhanced the main gateway logic to handle ACME challenges and manage TLS certificates using CertMagic. - Updated installation script to create necessary directories for ACME certificate storage and configure firewall rules for HTTP/HTTPS ports.
This commit is contained in:
parent
802f058345
commit
d2b671b335
@ -53,6 +53,7 @@ func parseGatewayConfig(logger *logging.ColoredLogger) *gateway.Config {
|
||||
ClientNamespace string `yaml:"client_namespace"`
|
||||
RQLiteDSN string `yaml:"rqlite_dsn"`
|
||||
BootstrapPeers []string `yaml:"bootstrap_peers"`
|
||||
Domain string `yaml:"domain"`
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(configPath)
|
||||
@ -103,6 +104,10 @@ func parseGatewayConfig(logger *logging.ColoredLogger) *gateway.Config {
|
||||
}
|
||||
}
|
||||
|
||||
if v := strings.TrimSpace(y.Domain); v != "" {
|
||||
cfg.Domain = v
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if errs := cfg.ValidateConfig(); len(errs) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "\nGateway configuration errors (%d):\n", len(errs))
|
||||
|
||||
@ -6,14 +6,19 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/DeBrosOfficial/network/pkg/gateway"
|
||||
"github.com/DeBrosOfficial/network/pkg/logging"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const acmeEmail = "dev@debros.io"
|
||||
|
||||
func setupLogger() *logging.ColoredLogger {
|
||||
logger, err := logging.NewColoredLogger(logging.ComponentGeneral, true)
|
||||
if err != nil {
|
||||
@ -42,9 +47,143 @@ func main() {
|
||||
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Creating HTTP server and routes...")
|
||||
|
||||
// Wrap handler with host enforcement if domain is set
|
||||
handler := gw.Routes()
|
||||
if cfg.Domain != "" {
|
||||
d := cfg.Domain
|
||||
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
host := r.Host
|
||||
if i := strings.IndexByte(host, ':'); i >= 0 {
|
||||
host = host[:i]
|
||||
}
|
||||
if !strings.EqualFold(host, d) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
gw.Routes().ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// If domain is configured, use ACME TLS on :443 and :80 for challenges
|
||||
if cfg.Domain != "" {
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Production ACME TLS enabled",
|
||||
zap.String("domain", cfg.Domain),
|
||||
zap.String("acme_email", acmeEmail),
|
||||
)
|
||||
|
||||
// Setup CertMagic with file storage
|
||||
certDir := filepath.Join(os.ExpandEnv("$HOME"), ".debros", "certmagic")
|
||||
if home, err := os.UserHomeDir(); err == nil {
|
||||
certDir = filepath.Join(home, ".debros", "certmagic")
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(certDir, 0700); err != nil {
|
||||
logger.ComponentError(logging.ComponentGeneral, "failed to create certmagic directory", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Configure CertMagic for ACME
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Provisioning ACME certificate...",
|
||||
zap.String("domain", cfg.Domain),
|
||||
)
|
||||
|
||||
// Use the default CertMagic instance and configure storage
|
||||
certmagic.Default.Storage = &certmagic.FileStorage{Path: certDir}
|
||||
|
||||
// Setup ACME issuer
|
||||
acmeIssuer := certmagic.ACMEIssuer{
|
||||
CA: certmagic.LetsEncryptProductionCA,
|
||||
Email: acmeEmail,
|
||||
Agreed: true,
|
||||
}
|
||||
certmagic.Default.Issuers = []certmagic.Issuer{&acmeIssuer}
|
||||
|
||||
// Manage the domain
|
||||
if err := certmagic.ManageSync(context.Background(), []string{cfg.Domain}); err != nil {
|
||||
logger.ComponentError(logging.ComponentGeneral, "ACME ManageSync failed", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Get TLS config
|
||||
tlsCfg := certmagic.Default.TLSConfig()
|
||||
|
||||
// Start HTTP server on :80 for ACME challenges and redirect to HTTPS
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Starting HTTP server on :80 for ACME challenges")
|
||||
go func() {
|
||||
httpMux := http.NewServeMux()
|
||||
httpMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Redirect all HTTP to HTTPS
|
||||
u := *r.URL
|
||||
u.Scheme = "https"
|
||||
u.Host = cfg.Domain
|
||||
http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
|
||||
})
|
||||
// HTTP server for ACME challenges and redirects
|
||||
if err := http.ListenAndServe(":80", httpMux); err != nil && err != http.ErrServerClosed {
|
||||
logger.ComponentError(logging.ComponentGeneral, "HTTP :80 server error", zap.Error(err))
|
||||
}
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "HTTP :80 server stopped")
|
||||
}()
|
||||
|
||||
// Start HTTPS server on :443
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Starting HTTPS server on :443 with ACME certificate",
|
||||
zap.String("domain", cfg.Domain),
|
||||
)
|
||||
|
||||
httpsServer := &http.Server{
|
||||
Addr: ":443",
|
||||
Handler: handler,
|
||||
TLSConfig: tlsCfg,
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", httpsServer.Addr)
|
||||
if err != nil {
|
||||
logger.ComponentError(logging.ComponentGeneral, "failed to bind HTTPS listen address", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "HTTPS listener bound", zap.String("listen_addr", ln.Addr().String()))
|
||||
|
||||
// Serve in a goroutine so we can handle graceful shutdown on signals.
|
||||
serveErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
if err := httpsServer.ServeTLS(ln, "", ""); err != nil && err != http.ErrServerClosed {
|
||||
serveErrCh <- err
|
||||
return
|
||||
}
|
||||
serveErrCh <- nil
|
||||
}()
|
||||
|
||||
// Wait for termination signal or server error
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
select {
|
||||
case sig := <-quit:
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "shutdown signal received", zap.String("signal", sig.String()))
|
||||
case err := <-serveErrCh:
|
||||
if err != nil {
|
||||
logger.ComponentError(logging.ComponentGeneral, "HTTPS server error", zap.Error(err))
|
||||
} else {
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "HTTPS server exited normally")
|
||||
}
|
||||
}
|
||||
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Shutting down gateway HTTPS server...")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := httpsServer.Shutdown(ctx); err != nil {
|
||||
logger.ComponentError(logging.ComponentGeneral, "HTTPS server shutdown error", zap.Error(err))
|
||||
} else {
|
||||
logger.ComponentInfo(logging.ComponentGeneral, "Gateway shutdown complete")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Fallback: HTTP server on configured listen_addr when no domain
|
||||
server := &http.Server{
|
||||
Addr: cfg.ListenAddr,
|
||||
Handler: gw.Routes(),
|
||||
Handler: handler,
|
||||
}
|
||||
|
||||
// Try to bind listener explicitly so binding failures are visible immediately.
|
||||
|
||||
4
go.mod
4
go.mod
@ -5,6 +5,7 @@ go 1.23.8
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/caddyserver/certmagic v0.20.0
|
||||
github.com/ethereum/go-ethereum v1.13.14
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/libp2p/go-libp2p v0.41.1
|
||||
@ -46,6 +47,7 @@ require (
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/koron/go-ssdp v0.0.5 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
|
||||
@ -55,6 +57,7 @@ require (
|
||||
github.com/libp2p/go-yamux/v5 v5.0.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/miekg/dns v1.1.66 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
@ -104,6 +107,7 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/dig v1.18.0 // indirect
|
||||
go.uber.org/fx v1.23.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
|
||||
13
go.sum
13
go.sum
@ -21,6 +21,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
|
||||
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
@ -123,6 +125,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk=
|
||||
@ -136,6 +139,8 @@ github.com/kr/pty v1.1.3/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/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
|
||||
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
|
||||
github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw=
|
||||
@ -165,6 +170,8 @@ github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
|
||||
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
|
||||
@ -342,6 +349,12 @@ github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguH
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw=
|
||||
go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
|
||||
@ -70,6 +70,13 @@ func (c *Config) ValidateConfig() []error {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate domain if provided (optional for TLS in production)
|
||||
if c.Domain != "" {
|
||||
if err := validateDomain(c.Domain); err != nil {
|
||||
errs = append(errs, fmt.Errorf("gateway.domain: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
@ -135,3 +142,31 @@ func extractTCPPort(multiaddrStr string) string {
|
||||
|
||||
return portPart[:firstSlashIndex]
|
||||
}
|
||||
|
||||
// validateDomain checks if a domain is valid (basic hostname validation).
|
||||
// Forbids schemes, slashes, and leading dots.
|
||||
func validateDomain(domain string) error {
|
||||
if strings.Contains(domain, "://") {
|
||||
return fmt.Errorf("domain must not contain a scheme (e.g., 'http://')")
|
||||
}
|
||||
if strings.Contains(domain, "/") {
|
||||
return fmt.Errorf("domain must not contain slashes")
|
||||
}
|
||||
if strings.HasPrefix(domain, ".") {
|
||||
return fmt.Errorf("domain must not start with a dot")
|
||||
}
|
||||
// Basic length check
|
||||
if len(domain) > 253 {
|
||||
return fmt.Errorf("domain is too long (max 253 characters)")
|
||||
}
|
||||
if len(domain) < 1 {
|
||||
return fmt.Errorf("domain must not be empty")
|
||||
}
|
||||
// Allow alphanumeric, dots, hyphens (basic hostname check)
|
||||
for _, ch := range domain {
|
||||
if !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
|
||||
return fmt.Errorf("domain contains invalid characters; only alphanumeric, dots, and hyphens allowed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -25,6 +25,9 @@ type Config struct {
|
||||
// Optional DSN for rqlite database/sql driver, e.g. "http://localhost:4001"
|
||||
// If empty, defaults to "http://localhost:4001".
|
||||
RQLiteDSN string
|
||||
|
||||
// Production domain for HTTPS/ACME
|
||||
Domain string
|
||||
}
|
||||
|
||||
type Gateway struct {
|
||||
|
||||
@ -251,7 +251,7 @@ install_rqlite() {
|
||||
}
|
||||
|
||||
check_ports() {
|
||||
local ports=($NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT)
|
||||
local ports=($NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT 80 443)
|
||||
for port in "${ports[@]}"; do
|
||||
if sudo netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
|
||||
error "Port $port is already in use. Please free it up and try again."
|
||||
@ -279,6 +279,10 @@ setup_directories() {
|
||||
sudo -u "$DEBROS_USER" mkdir -p "$DEBROS_HOME/.debros"
|
||||
sudo chmod 0700 "$DEBROS_HOME/.debros"
|
||||
|
||||
# Create ~/.debros/certmagic for ACME certificate storage
|
||||
sudo -u "$DEBROS_USER" mkdir -p "$DEBROS_HOME/.debros/certmagic"
|
||||
sudo chmod 0700 "$DEBROS_HOME/.debros/certmagic"
|
||||
|
||||
success "Directory structure ready"
|
||||
}
|
||||
|
||||
@ -354,7 +358,7 @@ configure_firewall() {
|
||||
log "Configuring firewall rules..."
|
||||
if command -v ufw &> /dev/null; then
|
||||
log "Adding UFW rules for DeBros Network ports..."
|
||||
for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT; do
|
||||
for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT 80 443; do
|
||||
if ! sudo ufw allow $port 2>/dev/null; then
|
||||
error "Failed to allow port $port"
|
||||
exit 1
|
||||
@ -375,6 +379,8 @@ configure_firewall() {
|
||||
log " - Port $RQLITE_PORT (RQLite HTTP)"
|
||||
log " - Port $RAFT_PORT (RQLite Raft)"
|
||||
log " - Port $GATEWAY_PORT (Gateway)"
|
||||
log " - Port 80 (HTTP - ACME challenges)"
|
||||
log " - Port 443 (HTTPS - Production TLS)"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -455,6 +461,10 @@ ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ReadWritePaths=/opt/debros
|
||||
|
||||
# Allow binding to privileged ports (80, 443) for ACME TLS
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
@ -538,8 +548,16 @@ main() {
|
||||
log "${GREEN}Config Directory:${NOCOLOR} ${CYAN}$DEBROS_HOME/.debros${NOCOLOR}"
|
||||
log "${GREEN}LibP2P Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}"
|
||||
log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}"
|
||||
log "${GREEN}Gateway Port:${NOCOLOR} ${CYAN}$GATEWAY_PORT${NOCOLOR}"
|
||||
log "${GREEN}Gateway Port (Dev):${NOCOLOR} ${CYAN}$GATEWAY_PORT${NOCOLOR}"
|
||||
log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}"
|
||||
log "${GREEN}HTTP/ACME (Production):${NOCOLOR} ${CYAN}80${NOCOLOR}"
|
||||
log "${GREEN}HTTPS/TLS (Production):${NOCOLOR} ${CYAN}443${NOCOLOR}"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN}Production ACME Setup:${NOCOLOR}"
|
||||
log "${CYAN} Edit $DEBROS_HOME/.debros/gateway.yaml and add:${NOCOLOR}"
|
||||
log "${CYAN} domain: \"api.example.com\"${NOCOLOR}"
|
||||
log "${CYAN} Ensure DNS A record points to this server IP${NOCOLOR}"
|
||||
log "${CYAN} Certificate will auto-provision on first gateway start${NOCOLOR}"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN}Service Management:${NOCOLOR}"
|
||||
log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check node status)"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user