mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 04:53:00 +00:00
fixed more bugs and updated docs
This commit is contained in:
parent
73dfe22438
commit
c401fdcd74
@ -452,15 +452,16 @@ make test-e2e # Run E2E tests
|
||||
|
||||
```bash
|
||||
# First node (genesis — creates cluster)
|
||||
sudo orama install --vps-ip <IP> --domain node1.example.com --nameserver
|
||||
# Nameserver nodes use the base domain as --domain
|
||||
sudo orama install --vps-ip <IP> --domain example.com --base-domain example.com --nameserver
|
||||
|
||||
# On the genesis node, generate an invite for a new node
|
||||
orama invite
|
||||
# Outputs: sudo orama install --join https://node1.example.com --token <TOKEN> --vps-ip <NEW_IP>
|
||||
# Outputs: sudo orama install --join https://example.com --token <TOKEN> --vps-ip <NEW_IP>
|
||||
|
||||
# Additional nodes (join via invite token over HTTPS)
|
||||
sudo orama install --join https://node1.example.com --token <TOKEN> \
|
||||
--vps-ip <IP> --nameserver
|
||||
# Additional nameserver nodes (join via invite token over HTTPS)
|
||||
sudo orama install --join https://example.com --token <TOKEN> \
|
||||
--vps-ip <IP> --domain example.com --base-domain example.com --nameserver
|
||||
```
|
||||
|
||||
**Security:** Nodes join via single-use invite tokens over HTTPS. A WireGuard VPN tunnel
|
||||
|
||||
@ -100,10 +100,10 @@ To deploy to all nodes, repeat steps 3-5 (dev) or 3-4 (production) for each VPS
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--vps-ip <ip>` | VPS public IP address (required) |
|
||||
| `--domain <domain>` | Domain for HTTPS certificates |
|
||||
| `--base-domain <domain>` | Base domain for deployment routing (e.g., dbrs.space) |
|
||||
| `--domain <domain>` | Domain for HTTPS certificates. Nameserver nodes use the base domain (e.g., `example.com`); non-nameserver nodes use a subdomain (e.g., `node-4.example.com`) |
|
||||
| `--base-domain <domain>` | Base domain for deployment routing (e.g., example.com) |
|
||||
| `--nameserver` | Configure this node as a nameserver (CoreDNS + Caddy) |
|
||||
| `--join <url>` | Join existing cluster via HTTPS URL (e.g., `https://node1.dbrs.space`) |
|
||||
| `--join <url>` | Join existing cluster via HTTPS URL (e.g., `https://node1.example.com`) |
|
||||
| `--token <token>` | Invite token for joining (from `orama invite` on existing node) |
|
||||
| `--branch <branch>` | Git branch to use (default: main) |
|
||||
| `--no-pull` | Skip git clone/pull, use existing `/home/debros/src` |
|
||||
@ -143,16 +143,18 @@ To deploy to all nodes, repeat steps 3-5 (dev) or 3-4 (production) for each VPS
|
||||
|
||||
```bash
|
||||
# 1. Genesis node (first node, creates cluster)
|
||||
sudo orama install --vps-ip 1.2.3.4 --domain node1.dbrs.space \
|
||||
--base-domain dbrs.space --nameserver
|
||||
# Nameserver nodes use the base domain as --domain
|
||||
sudo orama install --vps-ip 1.2.3.4 --domain example.com \
|
||||
--base-domain example.com --nameserver
|
||||
|
||||
# 2. On genesis node, generate an invite
|
||||
orama invite
|
||||
# Output: sudo orama install --join https://node1.dbrs.space --token <TOKEN> --vps-ip <IP>
|
||||
# Output: sudo orama install --join https://example.com --token <TOKEN> --vps-ip <IP>
|
||||
|
||||
# 3. On the new node, run the printed command
|
||||
sudo orama install --join https://node1.dbrs.space --token abc123... \
|
||||
--vps-ip 5.6.7.8 --nameserver
|
||||
# Nameserver nodes use the base domain; non-nameserver nodes use subdomains (e.g., node-4.example.com)
|
||||
sudo orama install --join https://example.com --token abc123... \
|
||||
--vps-ip 5.6.7.8 --domain example.com --base-domain example.com --nameserver
|
||||
```
|
||||
|
||||
The join flow establishes a WireGuard VPN tunnel before starting cluster services.
|
||||
@ -161,9 +163,9 @@ No cluster ports are ever exposed publicly.
|
||||
|
||||
#### DNS Prerequisite
|
||||
|
||||
The `--join` URL should use the HTTPS domain of the genesis node (e.g., `https://node1.dbrs.space`).
|
||||
For this to work, the domain registrar for `dbrs.space` must have NS records pointing to the genesis
|
||||
node's IP so that `node1.dbrs.space` resolves publicly.
|
||||
The `--join` URL should use the HTTPS domain of the genesis node (e.g., `https://node1.example.com`).
|
||||
For this to work, the domain registrar for `example.com` must have NS records pointing to the genesis
|
||||
node's IP so that `node1.example.com` resolves publicly.
|
||||
|
||||
**If DNS is not yet configured**, you can use the genesis node's public IP with HTTP as a fallback:
|
||||
|
||||
|
||||
@ -484,9 +484,9 @@ func promptForBaseDomain() string {
|
||||
fmt.Println("=================================")
|
||||
fmt.Println("Select the network environment for this node:")
|
||||
fmt.Println()
|
||||
fmt.Println(" 1. devnet-orama.network (Development - for testing)")
|
||||
fmt.Println(" 2. testnet-orama.network (Testnet - pre-production)")
|
||||
fmt.Println(" 3. mainnet-orama.network (Mainnet - production)")
|
||||
fmt.Println(" 1. orama-devnet.network (Development - for testing)")
|
||||
fmt.Println(" 2. orama-testnet.network (Testnet - pre-production)")
|
||||
fmt.Println(" 3. orama-mainnet.network (Mainnet - production)")
|
||||
fmt.Println(" 4. Custom domain...")
|
||||
fmt.Println()
|
||||
fmt.Print("Select option [1-4] (default: 1): ")
|
||||
@ -496,21 +496,21 @@ func promptForBaseDomain() string {
|
||||
|
||||
switch choice {
|
||||
case "", "1":
|
||||
fmt.Println("✓ Selected: devnet-orama.network")
|
||||
return "devnet-orama.network"
|
||||
fmt.Println("✓ Selected: orama-devnet.network")
|
||||
return "orama-devnet.network"
|
||||
case "2":
|
||||
fmt.Println("✓ Selected: testnet-orama.network")
|
||||
return "testnet-orama.network"
|
||||
fmt.Println("✓ Selected: orama-testnet.network")
|
||||
return "orama-testnet.network"
|
||||
case "3":
|
||||
fmt.Println("✓ Selected: mainnet-orama.network")
|
||||
return "mainnet-orama.network"
|
||||
fmt.Println("✓ Selected: orama-mainnet.network")
|
||||
return "orama-mainnet.network"
|
||||
case "4":
|
||||
fmt.Print("Enter custom base domain (e.g., example.com): ")
|
||||
customDomain, _ := reader.ReadString('\n')
|
||||
customDomain = strings.TrimSpace(customDomain)
|
||||
if customDomain == "" {
|
||||
fmt.Println("⚠️ No domain entered, using devnet-orama.network")
|
||||
return "devnet-orama.network"
|
||||
fmt.Println("⚠️ No domain entered, using orama-devnet.network")
|
||||
return "orama-devnet.network"
|
||||
}
|
||||
// Remove any protocol prefix if user included it
|
||||
customDomain = strings.TrimPrefix(customDomain, "https://")
|
||||
@ -519,7 +519,7 @@ func promptForBaseDomain() string {
|
||||
fmt.Printf("✓ Selected: %s\n", customDomain)
|
||||
return customDomain
|
||||
default:
|
||||
fmt.Println("⚠️ Invalid option, using devnet-orama.network")
|
||||
return "devnet-orama.network"
|
||||
fmt.Println("⚠️ Invalid option, using orama-devnet.network")
|
||||
return "orama-devnet.network"
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,6 +176,7 @@ func (cg *ConfigGenerator) GenerateNodeConfig(peerAddresses []string, vpsIP stri
|
||||
TLSCacheDir: tlsCacheDir,
|
||||
HTTPPort: httpPort,
|
||||
HTTPSPort: httpsPort,
|
||||
WGIP: vpsIP,
|
||||
}
|
||||
|
||||
// RQLite node-to-node TLS encryption is disabled by default
|
||||
|
||||
@ -504,7 +504,7 @@ func (ps *ProductionSetup) Phase4GenerateConfigs(peerAddresses []string, vpsIP s
|
||||
olricSeedPeers = olricPeers[0]
|
||||
}
|
||||
olricConfig, err := ps.configGenerator.GenerateOlricConfig(
|
||||
"127.0.0.1", // HTTP API on localhost
|
||||
vpsIP, // HTTP API on WG IP (unique per node, avoids memberlist name conflict)
|
||||
3320,
|
||||
vpsIP, // Memberlist on WG IP for clustering
|
||||
3322,
|
||||
|
||||
@ -70,7 +70,11 @@ http_gateway:
|
||||
client_namespace: "default"
|
||||
rqlite_dsn: "http://localhost:{{.RQLiteHTTPPort}}"
|
||||
olric_servers:
|
||||
{{- if .WGIP}}
|
||||
- "{{.WGIP}}:3320"
|
||||
{{- else}}
|
||||
- "127.0.0.1:3320"
|
||||
{{- end}}
|
||||
olric_timeout: "10s"
|
||||
ipfs_cluster_api_url: "http://localhost:{{.ClusterAPIPort}}"
|
||||
ipfs_api_url: "http://localhost:{{.IPFSAPIPort}}"
|
||||
|
||||
@ -32,6 +32,7 @@ type NodeConfigData struct {
|
||||
TLSCacheDir string // Directory for ACME certificate cache
|
||||
HTTPPort int // HTTP port for ACME challenges (usually 80)
|
||||
HTTPSPort int // HTTPS port (usually 443)
|
||||
WGIP string // WireGuard IP address (e.g., 10.0.0.1)
|
||||
|
||||
// Node-to-node TLS encryption for RQLite Raft communication
|
||||
// Required when using SNI gateway for Raft traffic routing
|
||||
|
||||
@ -10,7 +10,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/DeBrosOfficial/network/pkg/rqlite"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -406,12 +410,30 @@ func (h *Handler) queryIPFSClusterPeerInfo(myWGIP string) PeerInfo {
|
||||
}
|
||||
|
||||
// buildBootstrapPeers constructs bootstrap peer multiaddrs using WG IPs
|
||||
// Uses the node's LibP2P peer ID (port 4001), NOT the IPFS peer ID (port 4101)
|
||||
func (h *Handler) buildBootstrapPeers(myWGIP, ipfsPeerID string) []string {
|
||||
if ipfsPeerID == "" {
|
||||
// Read the node's LibP2P identity from disk
|
||||
keyPath := filepath.Join(h.oramaDir, "data", "identity.key")
|
||||
keyData, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
h.logger.Warn("Failed to read node identity for bootstrap peers", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
priv, err := crypto.UnmarshalPrivateKey(keyData)
|
||||
if err != nil {
|
||||
h.logger.Warn("Failed to unmarshal node identity key", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
peerID, err := peer.IDFromPublicKey(priv.GetPublic())
|
||||
if err != nil {
|
||||
h.logger.Warn("Failed to derive peer ID from identity key", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
return []string{
|
||||
fmt.Sprintf("/ip4/%s/tcp/4101/p2p/%s", myWGIP, ipfsPeerID),
|
||||
fmt.Sprintf("/ip4/%s/tcp/4001/p2p/%s", myWGIP, peerID.String()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ type InstanceConfig struct {
|
||||
Namespace string // Namespace name (e.g., "alice")
|
||||
NodeID string // Physical node ID
|
||||
HTTPPort int // HTTP API port
|
||||
BaseDomain string // Base domain (e.g., "devnet-orama.network")
|
||||
BaseDomain string // Base domain (e.g., "orama-devnet.network")
|
||||
RQLiteDSN string // RQLite connection DSN (e.g., "http://localhost:10000")
|
||||
OlricServers []string // Olric server addresses
|
||||
NodePeerID string // Physical node's peer ID for home node management
|
||||
|
||||
@ -20,7 +20,7 @@ import (
|
||||
|
||||
// ClusterManagerConfig contains configuration for the cluster manager
|
||||
type ClusterManagerConfig struct {
|
||||
BaseDomain string // Base domain for namespace gateways (e.g., "devnet-orama.network")
|
||||
BaseDomain string // Base domain for namespace gateways (e.g., "orama-devnet.network")
|
||||
BaseDataDir string // Base directory for namespace data (e.g., "~/.orama/data/namespaces")
|
||||
}
|
||||
|
||||
|
||||
@ -9,12 +9,12 @@ import (
|
||||
|
||||
func TestClusterManagerConfig(t *testing.T) {
|
||||
cfg := ClusterManagerConfig{
|
||||
BaseDomain: "devnet-orama.network",
|
||||
BaseDomain: "orama-devnet.network",
|
||||
BaseDataDir: "~/.orama/data/namespaces",
|
||||
}
|
||||
|
||||
if cfg.BaseDomain != "devnet-orama.network" {
|
||||
t.Errorf("BaseDomain = %s, want devnet-orama.network", cfg.BaseDomain)
|
||||
if cfg.BaseDomain != "orama-devnet.network" {
|
||||
t.Errorf("BaseDomain = %s, want orama-devnet.network", cfg.BaseDomain)
|
||||
}
|
||||
if cfg.BaseDataDir != "~/.orama/data/namespaces" {
|
||||
t.Errorf("BaseDataDir = %s, want ~/.orama/data/namespaces", cfg.BaseDataDir)
|
||||
@ -25,7 +25,7 @@ func TestNewClusterManager(t *testing.T) {
|
||||
mockDB := newMockRQLiteClient()
|
||||
logger := zap.NewNop()
|
||||
cfg := ClusterManagerConfig{
|
||||
BaseDomain: "devnet-orama.network",
|
||||
BaseDomain: "orama-devnet.network",
|
||||
BaseDataDir: "/tmp/test-namespaces",
|
||||
}
|
||||
|
||||
@ -288,10 +288,10 @@ func TestClusterManager_PortAllocationOrder(t *testing.T) {
|
||||
|
||||
func TestClusterManager_DNSFormat(t *testing.T) {
|
||||
// Test the DNS domain format for namespace gateways
|
||||
baseDomain := "devnet-orama.network"
|
||||
baseDomain := "orama-devnet.network"
|
||||
namespaceName := "alice"
|
||||
|
||||
expectedDomain := "ns-alice.devnet-orama.network"
|
||||
expectedDomain := "ns-alice.orama-devnet.network"
|
||||
actualDomain := "ns-" + namespaceName + "." + baseDomain
|
||||
|
||||
if actualDomain != expectedDomain {
|
||||
|
||||
@ -14,9 +14,9 @@ func TestDNSRecordManager_FQDNFormat(t *testing.T) {
|
||||
baseDomain string
|
||||
expected string
|
||||
}{
|
||||
{"alice", "devnet-orama.network", "ns-alice.devnet-orama.network."},
|
||||
{"bob", "testnet-orama.network", "ns-bob.testnet-orama.network."},
|
||||
{"my-namespace", "mainnet-orama.network", "ns-my-namespace.mainnet-orama.network."},
|
||||
{"alice", "orama-devnet.network", "ns-alice.orama-devnet.network."},
|
||||
{"bob", "orama-testnet.network", "ns-bob.orama-testnet.network."},
|
||||
{"my-namespace", "orama-mainnet.network", "ns-my-namespace.orama-mainnet.network."},
|
||||
{"test123", "example.com", "ns-test123.example.com."},
|
||||
}
|
||||
|
||||
@ -37,8 +37,8 @@ func TestDNSRecordManager_WildcardFQDNFormat(t *testing.T) {
|
||||
baseDomain string
|
||||
expected string
|
||||
}{
|
||||
{"alice", "devnet-orama.network", "*.ns-alice.devnet-orama.network."},
|
||||
{"bob", "testnet-orama.network", "*.ns-bob.testnet-orama.network."},
|
||||
{"alice", "orama-devnet.network", "*.ns-alice.orama-devnet.network."},
|
||||
{"bob", "orama-testnet.network", "*.ns-bob.orama-testnet.network."},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@ -54,7 +54,7 @@ func TestDNSRecordManager_WildcardFQDNFormat(t *testing.T) {
|
||||
func TestNewDNSRecordManager(t *testing.T) {
|
||||
mockDB := newMockRQLiteClient()
|
||||
logger := zap.NewNop()
|
||||
baseDomain := "devnet-orama.network"
|
||||
baseDomain := "orama-devnet.network"
|
||||
|
||||
manager := NewDNSRecordManager(mockDB, baseDomain, logger)
|
||||
|
||||
@ -88,9 +88,9 @@ func TestDNSRecordTTL(t *testing.T) {
|
||||
func TestDNSRecordManager_MultipleDomainFormats(t *testing.T) {
|
||||
// Test support for different domain formats
|
||||
baseDomains := []string{
|
||||
"devnet-orama.network",
|
||||
"testnet-orama.network",
|
||||
"mainnet-orama.network",
|
||||
"orama-devnet.network",
|
||||
"orama-testnet.network",
|
||||
"orama-mainnet.network",
|
||||
"custom.example.com",
|
||||
"subdomain.custom.example.com",
|
||||
}
|
||||
@ -203,7 +203,7 @@ func TestDNSRecordManager_FQDNWithTrailingDot(t *testing.T) {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"ns-alice.devnet-orama.network", "ns-alice.devnet-orama.network."},
|
||||
{"ns-alice.orama-devnet.network", "ns-alice.orama-devnet.network."},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@ -306,6 +306,11 @@ func extractIPForSort(raftAddr string) string {
|
||||
// IsVoter returns true if the given raft address is in the voter set
|
||||
// based on the current known peers. Must be called with c.mu held.
|
||||
func (c *ClusterDiscoveryService) IsVoterLocked(raftAddress string) bool {
|
||||
// If we don't know enough peers yet, default to voter.
|
||||
// Non-voter demotion only kicks in once we see more than MaxDefaultVoters peers.
|
||||
if len(c.knownPeers) <= MaxDefaultVoters {
|
||||
return true
|
||||
}
|
||||
raftAddrs := make([]string, 0, len(c.knownPeers))
|
||||
for _, peer := range c.knownPeers {
|
||||
raftAddrs = append(raftAddrs, peer.RaftAddress)
|
||||
|
||||
@ -122,7 +122,7 @@ func (r *RQLiteManager) launchProcess(ctx context.Context, rqliteDataDir string)
|
||||
if r.discoveryService != nil && !r.discoveryService.IsVoter(r.discoverConfig.RaftAdvAddress) {
|
||||
r.logger.Info("Joining as non-voter (read replica)",
|
||||
zap.String("raft_address", r.discoverConfig.RaftAdvAddress))
|
||||
args = append(args, "-non-voter")
|
||||
args = append(args, "-raft-non-voter")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user