feat: update RQLite configuration for direct TLS support

- Modified the RQLite node configuration to use direct TLS on port 7002 when HTTPS is enabled, bypassing SNI gateway conflicts.
- Updated the join address logic to reflect the new direct RQLite TLS connection method.
- Enhanced documentation comments to clarify the changes in TLS handling and port usage for Raft communication.
This commit is contained in:
anonpenguin23 2025-11-28 15:14:26 +02:00
parent 3ca4e1f43b
commit 3505a6a0eb
3 changed files with 51 additions and 17 deletions

View File

@ -106,13 +106,15 @@ func (cg *ConfigGenerator) GenerateNodeConfig(peerAddresses []string, vpsIP stri
}
// Determine advertise addresses - use vpsIP if provided
// When HTTPS/SNI is enabled, use domain-based raft address for SNI routing
// When HTTPS is enabled, RQLite uses native TLS on port 7002 (not SNI gateway)
// This avoids conflicts between SNI gateway TLS termination and RQLite's native TLS
var httpAdvAddr, raftAdvAddr string
if vpsIP != "" {
httpAdvAddr = net.JoinHostPort(vpsIP, "5001")
if enableHTTPS && domain != "" {
// Use SNI domain for Raft advertisement so other nodes connect via SNI gateway
raftAdvAddr = fmt.Sprintf("raft.%s:7001", domain)
if enableHTTPS {
// Use direct IP:7002 for Raft - RQLite handles TLS natively via -node-cert
// This bypasses the SNI gateway which would cause TLS termination conflicts
raftAdvAddr = net.JoinHostPort(vpsIP, "7002")
} else {
raftAdvAddr = net.JoinHostPort(vpsIP, "7001")
}
@ -123,15 +125,26 @@ func (cg *ConfigGenerator) GenerateNodeConfig(peerAddresses []string, vpsIP stri
}
// Determine RQLite join address
// When HTTPS is enabled, use port 7002 (direct RQLite TLS) instead of 7001 (SNI gateway)
joinPort := "7001"
if enableHTTPS {
joinPort = "7002"
}
var rqliteJoinAddr string
if joinAddress != "" {
// Use explicitly provided join address
rqliteJoinAddr = joinAddress
// If it contains :7001 and HTTPS is enabled, update to :7002
if enableHTTPS && strings.Contains(joinAddress, ":7001") {
rqliteJoinAddr = strings.Replace(joinAddress, ":7001", ":7002", 1)
} else {
rqliteJoinAddr = joinAddress
}
} else if len(peerAddresses) > 0 {
// Infer join address from peers
peerIP := inferPeerIP(peerAddresses, "")
if peerIP != "" {
rqliteJoinAddr = net.JoinHostPort(peerIP, "7001")
rqliteJoinAddr = net.JoinHostPort(peerIP, joinPort)
// Validate that join address doesn't match this node's own raft address (would cause self-join)
if rqliteJoinAddr == raftAdvAddr {
rqliteJoinAddr = "" // Clear it - this is the first node
@ -176,14 +189,13 @@ func (cg *ConfigGenerator) GenerateNodeConfig(peerAddresses []string, vpsIP stri
HTTPSPort: httpsPort,
}
// When HTTPS/SNI is enabled, configure RQLite node-to-node TLS encryption
// This allows Raft traffic to be routed through the SNI gateway
// Uses the same certificates as the SNI gateway (Let's Encrypt or self-signed)
// When HTTPS is enabled, configure RQLite node-to-node TLS encryption
// RQLite handles TLS natively on port 7002, bypassing the SNI gateway
// This avoids TLS termination conflicts between SNI gateway and RQLite
if enableHTTPS && domain != "" {
data.NodeCert = filepath.Join(tlsCacheDir, domain+".crt")
data.NodeKey = filepath.Join(tlsCacheDir, domain+".key")
// Skip verification since nodes may have different domain certificates
// and we're routing through the SNI gateway which terminates TLS
data.NodeNoVerify = true
}

View File

@ -15,7 +15,7 @@ database:
rqlite_port: {{.RQLiteHTTPPort}}
rqlite_raft_port: {{.RQLiteRaftInternalPort}}
rqlite_join_address: "{{.RQLiteJoinAddress}}"
{{if .NodeCert}}# Node-to-node TLS encryption for Raft communication (required for SNI gateway routing)
{{if .NodeCert}}# Node-to-node TLS encryption for Raft communication (direct RQLite TLS on port 7002)
node_cert: "{{.NodeCert}}"
node_key: "{{.NodeKey}}"
{{if .NodeCACert}}node_ca_cert: "{{.NodeCACert}}"
@ -68,7 +68,7 @@ http_gateway:
cert_file: "{{.TLSCacheDir}}/{{.Domain}}.crt"
key_file: "{{.TLSCacheDir}}/{{.Domain}}.key"
routes:
raft.{{.Domain}}: "localhost:{{.RQLiteRaftInternalPort}}"
# Note: Raft traffic bypasses SNI gateway - RQLite uses native TLS on port 7002
ipfs.{{.Domain}}: "localhost:4101"
ipfs-cluster.{{.Domain}}: "localhost:9096"
olric.{{.Domain}}: "localhost:3322"

View File

@ -25,7 +25,8 @@ type InstallerConfig struct {
VpsIP string
Domain string
PeerDomain string // Domain of existing node to join
JoinAddress string // Auto-populated: raft.{PeerDomain}:7001
PeerIP string // Resolved IP of peer domain (for Raft join)
JoinAddress string // Auto-populated: {PeerIP}:7002 (direct RQLite TLS)
Peers []string // Auto-populated: /dns4/{PeerDomain}/tcp/4001/p2p/{PeerID}
ClusterSecret string
SwarmKeyHex string // 64-hex IPFS swarm key (for joining private network)
@ -280,8 +281,28 @@ func (m *Model) handleEnter() (tea.Model, tea.Cmd) {
m.config.PeerDomain = peerDomain
m.discoveredPeer = discovery.PeerID
// Auto-populate join address and bootstrap peers
m.config.JoinAddress = fmt.Sprintf("raft.%s:7001", peerDomain)
// Resolve peer domain to IP for direct RQLite TLS connection
// RQLite uses native TLS on port 7002 (not SNI gateway on 7001)
peerIPs, err := net.LookupIP(peerDomain)
if err != nil || len(peerIPs) == 0 {
m.err = fmt.Errorf("failed to resolve peer domain %s to IP: %w", peerDomain, err)
return m, nil
}
// Prefer IPv4
var peerIP string
for _, ip := range peerIPs {
if ip.To4() != nil {
peerIP = ip.String()
break
}
}
if peerIP == "" {
peerIP = peerIPs[0].String()
}
m.config.PeerIP = peerIP
// Auto-populate join address (direct RQLite TLS on port 7002) and bootstrap peers
m.config.JoinAddress = fmt.Sprintf("%s:7002", peerIP)
m.config.Peers = []string{
fmt.Sprintf("/dns4/%s/tcp/4001/p2p/%s", peerDomain, discovery.PeerID),
}
@ -836,12 +857,13 @@ func detectPublicIP() string {
}
// validateSNIDNSRecords checks if the required SNI DNS records exist
// It tries to resolve the key SNI hostnames for RQLite, IPFS, IPFS Cluster, and Olric
// It tries to resolve the key SNI hostnames for IPFS, IPFS Cluster, and Olric
// Note: Raft no longer uses SNI - it uses direct RQLite TLS on port 7002
// All should resolve to the same IP (the node's public IP or domain)
func validateSNIDNSRecords(domain string) error {
// List of SNI services that need DNS records
// Note: raft.domain is NOT included - RQLite uses direct TLS on port 7002
sniServices := []string{
fmt.Sprintf("raft.%s", domain),
fmt.Sprintf("ipfs.%s", domain),
fmt.Sprintf("ipfs-cluster.%s", domain),
fmt.Sprintf("olric.%s", domain),