mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 03:43:04 +00:00
added support for anyone relay with rewards
This commit is contained in:
parent
c827651245
commit
468ca06398
4
.gitignore
vendored
4
.gitignore
vendored
@ -90,4 +90,6 @@ scripts/remote-nodes.conf
|
||||
|
||||
orama-cli-linux
|
||||
|
||||
rnd/
|
||||
rnd/
|
||||
|
||||
keys_backup/
|
||||
48
README.md
48
README.md
@ -324,10 +324,56 @@ curl -X DELETE http://localhost:6001/v1/functions/hello-world?namespace=default
|
||||
- 5001 - RQLite HTTP API
|
||||
- 6001 - Unified Gateway
|
||||
- 8080 - IPFS Gateway
|
||||
- 9050 - Anyone Client SOCKS5 proxy
|
||||
- 9050 - Anyone SOCKS5 proxy
|
||||
- 9094 - IPFS Cluster API
|
||||
- 3320/3322 - Olric Cache
|
||||
|
||||
**Anyone Relay Mode (optional, for earning rewards):**
|
||||
|
||||
- 9001 - Anyone ORPort (relay traffic, must be open externally)
|
||||
|
||||
### Anyone Network Integration
|
||||
|
||||
Orama Network integrates with the [Anyone Protocol](https://anyone.io) for anonymous routing. By default, nodes run as **clients** (consuming the network). Optionally, you can run as a **relay operator** to earn rewards.
|
||||
|
||||
**Client Mode (Default):**
|
||||
- Routes traffic through Anyone network for anonymity
|
||||
- SOCKS5 proxy on localhost:9050
|
||||
- No rewards, just consumes network
|
||||
|
||||
**Relay Mode (Earn Rewards):**
|
||||
- Provide bandwidth to the Anyone network
|
||||
- Earn $ANYONE tokens as a relay operator
|
||||
- Requires 100 $ANYONE tokens in your wallet
|
||||
- Requires ORPort (9001) open to the internet
|
||||
|
||||
```bash
|
||||
# Install as relay operator (earn rewards)
|
||||
sudo orama install --vps-ip <IP> --domain <domain> \
|
||||
--anyone-relay \
|
||||
--anyone-nickname "MyRelay" \
|
||||
--anyone-contact "operator@email.com" \
|
||||
--anyone-wallet "0x1234...abcd"
|
||||
|
||||
# With exit relay (legal implications apply)
|
||||
sudo orama install --vps-ip <IP> --domain <domain> \
|
||||
--anyone-relay \
|
||||
--anyone-exit \
|
||||
--anyone-nickname "MyExitRelay" \
|
||||
--anyone-contact "operator@email.com" \
|
||||
--anyone-wallet "0x1234...abcd"
|
||||
|
||||
# Migrate existing Anyone installation
|
||||
sudo orama install --vps-ip <IP> --domain <domain> \
|
||||
--anyone-relay \
|
||||
--anyone-migrate \
|
||||
--anyone-nickname "MyRelay" \
|
||||
--anyone-contact "operator@email.com" \
|
||||
--anyone-wallet "0x1234...abcd"
|
||||
```
|
||||
|
||||
**Important:** After installation, register your relay at [dashboard.anyone.io](https://dashboard.anyone.io) to start earning rewards.
|
||||
|
||||
### Installation
|
||||
|
||||
**macOS (Homebrew):**
|
||||
|
||||
@ -52,6 +52,13 @@ The system follows a clean, layered architecture with clear separation of concer
|
||||
│ │ │ │
|
||||
│ Port 9094 │ │ In-Process │
|
||||
└─────────────────┘ └──────────────┘
|
||||
|
||||
┌─────────────────┐
|
||||
│ Anyone │
|
||||
│ (Anonymity) │
|
||||
│ │
|
||||
│ Port 9050 │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## Core Components
|
||||
@ -226,7 +233,38 @@ pkg/config/
|
||||
└── gateway.go
|
||||
```
|
||||
|
||||
### 6. Shared Utilities
|
||||
### 6. Anyone Integration (`pkg/anyoneproxy/`)
|
||||
|
||||
Integration with the Anyone Protocol for anonymous routing.
|
||||
|
||||
**Modes:**
|
||||
|
||||
| Mode | Purpose | Port | Rewards |
|
||||
|------|---------|------|---------|
|
||||
| Client | Route traffic anonymously | 9050 (SOCKS5) | No |
|
||||
| Relay | Provide bandwidth to network | 9001 (ORPort) + 9050 | Yes ($ANYONE) |
|
||||
|
||||
**Key Files:**
|
||||
- `pkg/anyoneproxy/socks.go` - SOCKS5 proxy client interface
|
||||
- `pkg/gateway/anon_proxy_handler.go` - Anonymous proxy API endpoint
|
||||
- `pkg/environments/production/installers/anyone_relay.go` - Relay installation
|
||||
|
||||
**Features:**
|
||||
- Smart routing (bypasses proxy for local/private addresses)
|
||||
- Automatic detection of existing Anyone installations
|
||||
- Migration support for existing relay operators
|
||||
- Exit relay mode with legal warnings
|
||||
|
||||
**API Endpoint:**
|
||||
- `POST /v1/proxy/anon` - Route HTTP requests through Anyone network
|
||||
|
||||
**Relay Requirements:**
|
||||
- Linux OS (Debian/Ubuntu)
|
||||
- 100 $ANYONE tokens in wallet
|
||||
- ORPort accessible from internet
|
||||
- Registration at dashboard.anyone.io
|
||||
|
||||
### 7. Shared Utilities
|
||||
|
||||
**HTTP Utilities (`pkg/httputil/`):**
|
||||
- Request parsing and validation
|
||||
|
||||
@ -39,6 +39,12 @@ func Handle(args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Validate Anyone relay configuration if enabled
|
||||
if err := orchestrator.validator.ValidateAnyoneRelayFlags(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Execute installation
|
||||
if err := orchestrator.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||
|
||||
@ -27,6 +27,16 @@ type Flags struct {
|
||||
IPFSAddrs string
|
||||
IPFSClusterPeerID string
|
||||
IPFSClusterAddrs string
|
||||
|
||||
// Anyone relay operator flags
|
||||
AnyoneRelay bool // Run as relay operator instead of client
|
||||
AnyoneExit bool // Run as exit relay (legal implications)
|
||||
AnyoneMigrate bool // Migrate existing Anyone installation
|
||||
AnyoneNickname string // Relay nickname (1-19 alphanumeric)
|
||||
AnyoneContact string // Contact info (email or @telegram)
|
||||
AnyoneWallet string // Ethereum wallet for rewards
|
||||
AnyoneORPort int // ORPort for relay (default 9001)
|
||||
AnyoneFamily string // Comma-separated fingerprints of other relays you operate
|
||||
}
|
||||
|
||||
// ParseFlags parses install command flags
|
||||
@ -58,6 +68,16 @@ func ParseFlags(args []string) (*Flags, error) {
|
||||
fs.StringVar(&flags.IPFSClusterPeerID, "ipfs-cluster-peer", "", "Peer ID of existing IPFS Cluster node")
|
||||
fs.StringVar(&flags.IPFSClusterAddrs, "ipfs-cluster-addrs", "", "Comma-separated multiaddrs of existing IPFS Cluster node")
|
||||
|
||||
// Anyone relay operator flags
|
||||
fs.BoolVar(&flags.AnyoneRelay, "anyone-relay", false, "Run as Anyone relay operator (earn rewards)")
|
||||
fs.BoolVar(&flags.AnyoneExit, "anyone-exit", false, "Run as exit relay (requires --anyone-relay, legal implications)")
|
||||
fs.BoolVar(&flags.AnyoneMigrate, "anyone-migrate", false, "Migrate existing Anyone installation into Orama Network")
|
||||
fs.StringVar(&flags.AnyoneNickname, "anyone-nickname", "", "Relay nickname (1-19 alphanumeric chars)")
|
||||
fs.StringVar(&flags.AnyoneContact, "anyone-contact", "", "Contact info (email or @telegram)")
|
||||
fs.StringVar(&flags.AnyoneWallet, "anyone-wallet", "", "Ethereum wallet address for rewards")
|
||||
fs.IntVar(&flags.AnyoneORPort, "anyone-orport", 9001, "ORPort for relay (default 9001)")
|
||||
fs.StringVar(&flags.AnyoneFamily, "anyone-family", "", "Comma-separated fingerprints of other relays you operate")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
if err == flag.ErrHelp {
|
||||
return nil, err
|
||||
|
||||
@ -33,6 +33,21 @@ func NewOrchestrator(flags *Flags) (*Orchestrator, error) {
|
||||
|
||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.Branch, flags.NoPull, flags.SkipChecks)
|
||||
setup.SetNameserver(flags.Nameserver)
|
||||
|
||||
// Configure Anyone relay if enabled
|
||||
if flags.AnyoneRelay {
|
||||
setup.SetAnyoneRelayConfig(&production.AnyoneRelayConfig{
|
||||
Enabled: true,
|
||||
Exit: flags.AnyoneExit,
|
||||
Migrate: flags.AnyoneMigrate,
|
||||
Nickname: flags.AnyoneNickname,
|
||||
Contact: flags.AnyoneContact,
|
||||
Wallet: flags.AnyoneWallet,
|
||||
ORPort: flags.AnyoneORPort,
|
||||
MyFamily: flags.AnyoneFamily,
|
||||
})
|
||||
}
|
||||
|
||||
validator := NewValidator(flags, oramaDir)
|
||||
|
||||
return &Orchestrator{
|
||||
@ -60,7 +75,18 @@ func (o *Orchestrator) Execute() error {
|
||||
|
||||
// Dry-run mode: show what would be done and exit
|
||||
if o.flags.DryRun {
|
||||
utils.ShowDryRunSummary(o.flags.VpsIP, o.flags.Domain, o.flags.Branch, o.peers, o.flags.JoinAddress, o.validator.IsFirstNode(), o.oramaDir)
|
||||
var relayInfo *utils.AnyoneRelayDryRunInfo
|
||||
if o.flags.AnyoneRelay {
|
||||
relayInfo = &utils.AnyoneRelayDryRunInfo{
|
||||
Enabled: true,
|
||||
Exit: o.flags.AnyoneExit,
|
||||
Nickname: o.flags.AnyoneNickname,
|
||||
Contact: o.flags.AnyoneContact,
|
||||
Wallet: o.flags.AnyoneWallet,
|
||||
ORPort: o.flags.AnyoneORPort,
|
||||
}
|
||||
}
|
||||
utils.ShowDryRunSummaryWithRelay(o.flags.VpsIP, o.flags.Domain, o.flags.Branch, o.peers, o.flags.JoinAddress, o.validator.IsFirstNode(), o.oramaDir, relayInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/DeBrosOfficial/network/pkg/cli/utils"
|
||||
"github.com/DeBrosOfficial/network/pkg/environments/production/installers"
|
||||
)
|
||||
|
||||
// Validator validates install command inputs
|
||||
@ -43,7 +44,17 @@ func (v *Validator) ValidateRootPrivileges() error {
|
||||
|
||||
// ValidatePorts validates port availability
|
||||
func (v *Validator) ValidatePorts() error {
|
||||
if err := utils.EnsurePortsAvailable("install", utils.DefaultPorts()); err != nil {
|
||||
ports := utils.DefaultPorts()
|
||||
|
||||
// Add ORPort check for relay mode (skip if migrating existing installation)
|
||||
if v.flags.AnyoneRelay && !v.flags.AnyoneMigrate {
|
||||
ports = append(ports, utils.PortSpec{
|
||||
Name: "Anyone ORPort",
|
||||
Port: v.flags.AnyoneORPort,
|
||||
})
|
||||
}
|
||||
|
||||
if err := utils.EnsurePortsAvailable("install", ports); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -104,3 +115,107 @@ func (v *Validator) SaveSecrets() error {
|
||||
func (v *Validator) IsFirstNode() bool {
|
||||
return v.isFirstNode
|
||||
}
|
||||
|
||||
// ValidateAnyoneRelayFlags validates Anyone relay configuration and displays warnings
|
||||
func (v *Validator) ValidateAnyoneRelayFlags() error {
|
||||
// Skip validation if not running as relay
|
||||
if !v.flags.AnyoneRelay {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("\n🔗 Anyone Relay Configuration\n")
|
||||
|
||||
// Check for existing Anyone installation
|
||||
existing, err := installers.DetectExistingAnyoneInstallation()
|
||||
if err != nil {
|
||||
fmt.Printf(" ⚠️ Warning: failed to detect existing installation: %v\n", err)
|
||||
}
|
||||
|
||||
if existing != nil {
|
||||
fmt.Printf(" ⚠️ Existing Anyone relay detected:\n")
|
||||
if existing.Fingerprint != "" {
|
||||
fmt.Printf(" Fingerprint: %s\n", existing.Fingerprint)
|
||||
}
|
||||
if existing.Nickname != "" {
|
||||
fmt.Printf(" Nickname: %s\n", existing.Nickname)
|
||||
}
|
||||
if existing.Wallet != "" {
|
||||
fmt.Printf(" Wallet: %s\n", existing.Wallet)
|
||||
}
|
||||
if existing.MyFamily != "" {
|
||||
familyCount := len(strings.Split(existing.MyFamily, ","))
|
||||
fmt.Printf(" MyFamily: %d relays\n", familyCount)
|
||||
}
|
||||
fmt.Printf(" Keys: %s\n", existing.KeysPath)
|
||||
fmt.Printf(" Config: %s\n", existing.ConfigPath)
|
||||
if existing.IsRunning {
|
||||
fmt.Printf(" Status: Running\n")
|
||||
}
|
||||
if !v.flags.AnyoneMigrate {
|
||||
fmt.Printf("\n 💡 Use --anyone-migrate to preserve existing keys and fingerprint\n")
|
||||
} else {
|
||||
fmt.Printf("\n ✓ Will migrate existing installation (keys preserved)\n")
|
||||
// Auto-populate missing values from existing installation
|
||||
if v.flags.AnyoneNickname == "" && existing.Nickname != "" {
|
||||
v.flags.AnyoneNickname = existing.Nickname
|
||||
fmt.Printf(" ✓ Using existing nickname: %s\n", existing.Nickname)
|
||||
}
|
||||
if v.flags.AnyoneWallet == "" && existing.Wallet != "" {
|
||||
v.flags.AnyoneWallet = existing.Wallet
|
||||
fmt.Printf(" ✓ Using existing wallet: %s\n", existing.Wallet)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Validate required fields for relay mode
|
||||
if v.flags.AnyoneNickname == "" {
|
||||
return fmt.Errorf("--anyone-nickname is required for relay mode")
|
||||
}
|
||||
if err := installers.ValidateNickname(v.flags.AnyoneNickname); err != nil {
|
||||
return fmt.Errorf("invalid --anyone-nickname: %w", err)
|
||||
}
|
||||
|
||||
if v.flags.AnyoneWallet == "" {
|
||||
return fmt.Errorf("--anyone-wallet is required for relay mode (for rewards)")
|
||||
}
|
||||
if err := installers.ValidateWallet(v.flags.AnyoneWallet); err != nil {
|
||||
return fmt.Errorf("invalid --anyone-wallet: %w", err)
|
||||
}
|
||||
|
||||
if v.flags.AnyoneContact == "" {
|
||||
return fmt.Errorf("--anyone-contact is required for relay mode")
|
||||
}
|
||||
|
||||
// Validate ORPort
|
||||
if v.flags.AnyoneORPort < 1 || v.flags.AnyoneORPort > 65535 {
|
||||
return fmt.Errorf("--anyone-orport must be between 1 and 65535")
|
||||
}
|
||||
|
||||
// Display configuration summary
|
||||
fmt.Printf(" Nickname: %s\n", v.flags.AnyoneNickname)
|
||||
fmt.Printf(" Contact: %s\n", v.flags.AnyoneContact)
|
||||
fmt.Printf(" Wallet: %s\n", v.flags.AnyoneWallet)
|
||||
fmt.Printf(" ORPort: %d\n", v.flags.AnyoneORPort)
|
||||
if v.flags.AnyoneExit {
|
||||
fmt.Printf(" Mode: Exit Relay\n")
|
||||
} else {
|
||||
fmt.Printf(" Mode: Non-exit Relay\n")
|
||||
}
|
||||
|
||||
// Warning about token requirement
|
||||
fmt.Printf("\n ⚠️ IMPORTANT: Relay operators must hold 100 $ANYONE tokens\n")
|
||||
fmt.Printf(" in wallet %s to receive rewards.\n", v.flags.AnyoneWallet)
|
||||
fmt.Printf(" Register at: https://dashboard.anyone.io\n")
|
||||
|
||||
// Exit relay warning
|
||||
if v.flags.AnyoneExit {
|
||||
fmt.Printf("\n ⚠️ EXIT RELAY WARNING:\n")
|
||||
fmt.Printf(" Running an exit relay may expose you to legal liability\n")
|
||||
fmt.Printf(" for traffic that exits through your node.\n")
|
||||
fmt.Printf(" Ensure you understand the implications before proceeding.\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -13,6 +13,16 @@ type Flags struct {
|
||||
NoPull bool
|
||||
Branch string
|
||||
Nameserver *bool // Pointer so we can detect if explicitly set vs default
|
||||
|
||||
// Anyone relay operator flags
|
||||
AnyoneRelay bool
|
||||
AnyoneExit bool
|
||||
AnyoneMigrate bool
|
||||
AnyoneNickname string
|
||||
AnyoneContact string
|
||||
AnyoneWallet string
|
||||
AnyoneORPort int
|
||||
AnyoneFamily string
|
||||
}
|
||||
|
||||
// ParseFlags parses upgrade command flags
|
||||
@ -30,6 +40,16 @@ func ParseFlags(args []string) (*Flags, error) {
|
||||
// Nameserver flag - use pointer to detect if explicitly set
|
||||
nameserver := fs.Bool("nameserver", false, "Make this node a nameserver (uses saved preference if not specified)")
|
||||
|
||||
// Anyone relay operator flags
|
||||
fs.BoolVar(&flags.AnyoneRelay, "anyone-relay", false, "Run as Anyone relay operator (earn rewards)")
|
||||
fs.BoolVar(&flags.AnyoneExit, "anyone-exit", false, "Run as exit relay (requires --anyone-relay, legal implications)")
|
||||
fs.BoolVar(&flags.AnyoneMigrate, "anyone-migrate", false, "Migrate existing Anyone installation into Orama Network")
|
||||
fs.StringVar(&flags.AnyoneNickname, "anyone-nickname", "", "Relay nickname (1-19 alphanumeric chars)")
|
||||
fs.StringVar(&flags.AnyoneContact, "anyone-contact", "", "Contact info (email or @telegram)")
|
||||
fs.StringVar(&flags.AnyoneWallet, "anyone-wallet", "", "Ethereum wallet address for rewards")
|
||||
fs.IntVar(&flags.AnyoneORPort, "anyone-orport", 9001, "ORPort for relay (default 9001)")
|
||||
fs.StringVar(&flags.AnyoneFamily, "anyone-family", "", "Comma-separated fingerprints of other relays you operate")
|
||||
|
||||
// Support legacy flags for backwards compatibility
|
||||
nightly := fs.Bool("nightly", false, "Use nightly branch (deprecated, use --branch nightly)")
|
||||
main := fs.Bool("main", false, "Use main branch (deprecated, use --branch main)")
|
||||
|
||||
@ -44,6 +44,20 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
|
||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, branch, flags.NoPull, false)
|
||||
setup.SetNameserver(isNameserver)
|
||||
|
||||
// Configure Anyone relay if enabled
|
||||
if flags.AnyoneRelay {
|
||||
setup.SetAnyoneRelayConfig(&production.AnyoneRelayConfig{
|
||||
Enabled: true,
|
||||
Exit: flags.AnyoneExit,
|
||||
Migrate: flags.AnyoneMigrate,
|
||||
Nickname: flags.AnyoneNickname,
|
||||
Contact: flags.AnyoneContact,
|
||||
Wallet: flags.AnyoneWallet,
|
||||
ORPort: flags.AnyoneORPort,
|
||||
MyFamily: flags.AnyoneFamily,
|
||||
})
|
||||
}
|
||||
|
||||
return &Orchestrator{
|
||||
oramaHome: oramaHome,
|
||||
oramaDir: oramaDir,
|
||||
@ -192,7 +206,8 @@ func (o *Orchestrator) stopServices() error {
|
||||
"debros-ipfs-cluster.service", // Depends on IPFS
|
||||
"debros-ipfs.service", // Base IPFS
|
||||
"debros-olric.service", // Independent
|
||||
"debros-anyone-client.service", // Independent
|
||||
"debros-anyone-client.service", // Client mode
|
||||
"debros-anyone-relay.service", // Relay mode
|
||||
}
|
||||
for _, svc := range services {
|
||||
unitPath := filepath.Join("/etc/systemd/system", svc)
|
||||
|
||||
@ -17,8 +17,23 @@ type IPFSClusterPeerInfo struct {
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
// AnyoneRelayDryRunInfo contains Anyone relay info for dry-run summary
|
||||
type AnyoneRelayDryRunInfo struct {
|
||||
Enabled bool
|
||||
Exit bool
|
||||
Nickname string
|
||||
Contact string
|
||||
Wallet string
|
||||
ORPort int
|
||||
}
|
||||
|
||||
// ShowDryRunSummary displays what would be done during installation without making changes
|
||||
func ShowDryRunSummary(vpsIP, domain, branch string, peers []string, joinAddress string, isFirstNode bool, oramaDir string) {
|
||||
ShowDryRunSummaryWithRelay(vpsIP, domain, branch, peers, joinAddress, isFirstNode, oramaDir, nil)
|
||||
}
|
||||
|
||||
// ShowDryRunSummaryWithRelay displays what would be done during installation with optional relay info
|
||||
func ShowDryRunSummaryWithRelay(vpsIP, domain, branch string, peers []string, joinAddress string, isFirstNode bool, oramaDir string, relayInfo *AnyoneRelayDryRunInfo) {
|
||||
fmt.Print("\n" + strings.Repeat("=", 70) + "\n")
|
||||
fmt.Printf("DRY RUN - No changes will be made\n")
|
||||
fmt.Print(strings.Repeat("=", 70) + "\n\n")
|
||||
@ -57,7 +72,11 @@ func ShowDryRunSummary(vpsIP, domain, branch string, peers []string, joinAddress
|
||||
fmt.Printf(" - IPFS/Kubo 0.38.2\n")
|
||||
fmt.Printf(" - IPFS Cluster (latest)\n")
|
||||
fmt.Printf(" - Olric 0.7.0\n")
|
||||
fmt.Printf(" - anyone-client (npm)\n")
|
||||
if relayInfo != nil && relayInfo.Enabled {
|
||||
fmt.Printf(" - anon (relay binary via apt)\n")
|
||||
} else {
|
||||
fmt.Printf(" - anyone-client (npm)\n")
|
||||
}
|
||||
fmt.Printf(" - DeBros binaries (built from %s branch)\n", branch)
|
||||
|
||||
fmt.Printf("\n🔐 Secrets that would be generated:\n")
|
||||
@ -74,7 +93,11 @@ func ShowDryRunSummary(vpsIP, domain, branch string, peers []string, joinAddress
|
||||
fmt.Printf(" - debros-ipfs-cluster.service\n")
|
||||
fmt.Printf(" - debros-olric.service\n")
|
||||
fmt.Printf(" - debros-node.service (includes embedded gateway + RQLite)\n")
|
||||
fmt.Printf(" - debros-anyone-client.service\n")
|
||||
if relayInfo != nil && relayInfo.Enabled {
|
||||
fmt.Printf(" - debros-anyone-relay.service (relay operator mode)\n")
|
||||
} else {
|
||||
fmt.Printf(" - debros-anyone-client.service\n")
|
||||
}
|
||||
|
||||
fmt.Printf("\n🌐 Ports that would be used:\n")
|
||||
fmt.Printf(" External (must be open in firewall):\n")
|
||||
@ -82,6 +105,9 @@ func ShowDryRunSummary(vpsIP, domain, branch string, peers []string, joinAddress
|
||||
fmt.Printf(" - 443 (HTTPS gateway)\n")
|
||||
fmt.Printf(" - 4101 (IPFS swarm)\n")
|
||||
fmt.Printf(" - 7001 (RQLite Raft)\n")
|
||||
if relayInfo != nil && relayInfo.Enabled {
|
||||
fmt.Printf(" - %d (Anyone ORPort - relay traffic)\n", relayInfo.ORPort)
|
||||
}
|
||||
fmt.Printf(" Internal (localhost only):\n")
|
||||
fmt.Printf(" - 4501 (IPFS API)\n")
|
||||
fmt.Printf(" - 5001 (RQLite HTTP)\n")
|
||||
@ -91,6 +117,23 @@ func ShowDryRunSummary(vpsIP, domain, branch string, peers []string, joinAddress
|
||||
fmt.Printf(" - 9094 (IPFS Cluster API)\n")
|
||||
fmt.Printf(" - 3320/3322 (Olric)\n")
|
||||
|
||||
// Show relay-specific configuration
|
||||
if relayInfo != nil && relayInfo.Enabled {
|
||||
fmt.Printf("\n🔗 Anyone Relay Configuration:\n")
|
||||
fmt.Printf(" Mode: Relay Operator\n")
|
||||
fmt.Printf(" Nickname: %s\n", relayInfo.Nickname)
|
||||
fmt.Printf(" Contact: %s\n", relayInfo.Contact)
|
||||
fmt.Printf(" Wallet: %s\n", relayInfo.Wallet)
|
||||
fmt.Printf(" ORPort: %d\n", relayInfo.ORPort)
|
||||
if relayInfo.Exit {
|
||||
fmt.Printf(" Exit: Yes (legal implications apply)\n")
|
||||
} else {
|
||||
fmt.Printf(" Exit: No (non-exit relay)\n")
|
||||
}
|
||||
fmt.Printf("\n ⚠️ IMPORTANT: You need 100 $ANYONE tokens in wallet to receive rewards\n")
|
||||
fmt.Printf(" Register at: https://dashboard.anyone.io\n")
|
||||
}
|
||||
|
||||
fmt.Print("\n" + strings.Repeat("=", 70) + "\n")
|
||||
fmt.Printf("To proceed with installation, run without --dry-run\n")
|
||||
fmt.Print(strings.Repeat("=", 70) + "\n\n")
|
||||
|
||||
@ -160,6 +160,7 @@ func GetProductionServices() []string {
|
||||
"debros-ipfs-cluster",
|
||||
"debros-ipfs",
|
||||
"debros-anyone-client",
|
||||
"debros-anyone-relay",
|
||||
}
|
||||
|
||||
// Filter to only existing services by checking if unit file exists
|
||||
|
||||
385
pkg/environments/production/installers/anyone_relay.go
Normal file
385
pkg/environments/production/installers/anyone_relay.go
Normal file
@ -0,0 +1,385 @@
|
||||
package installers
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AnyoneRelayConfig holds configuration for the Anyone relay
|
||||
type AnyoneRelayConfig struct {
|
||||
Nickname string // Relay nickname (1-19 alphanumeric)
|
||||
Contact string // Contact info (email or @telegram)
|
||||
Wallet string // Ethereum wallet for rewards
|
||||
ORPort int // ORPort for relay (default 9001)
|
||||
ExitRelay bool // Whether to run as exit relay
|
||||
Migrate bool // Whether to migrate existing installation
|
||||
MyFamily string // Comma-separated list of family fingerprints (for multi-relay operators)
|
||||
}
|
||||
|
||||
// ExistingAnyoneInfo contains information about an existing Anyone installation
|
||||
type ExistingAnyoneInfo struct {
|
||||
HasKeys bool
|
||||
HasConfig bool
|
||||
IsRunning bool
|
||||
Fingerprint string
|
||||
Wallet string
|
||||
Nickname string
|
||||
MyFamily string // Existing MyFamily setting (important to preserve!)
|
||||
ConfigPath string
|
||||
KeysPath string
|
||||
}
|
||||
|
||||
// AnyoneRelayInstaller handles Anyone relay installation
|
||||
type AnyoneRelayInstaller struct {
|
||||
*BaseInstaller
|
||||
config AnyoneRelayConfig
|
||||
}
|
||||
|
||||
// NewAnyoneRelayInstaller creates a new Anyone relay installer
|
||||
func NewAnyoneRelayInstaller(arch string, logWriter io.Writer, config AnyoneRelayConfig) *AnyoneRelayInstaller {
|
||||
return &AnyoneRelayInstaller{
|
||||
BaseInstaller: NewBaseInstaller(arch, logWriter),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// DetectExistingAnyoneInstallation checks for an existing Anyone relay installation
|
||||
func DetectExistingAnyoneInstallation() (*ExistingAnyoneInfo, error) {
|
||||
info := &ExistingAnyoneInfo{
|
||||
ConfigPath: "/etc/anon/anonrc",
|
||||
KeysPath: "/var/lib/anon/keys",
|
||||
}
|
||||
|
||||
// Check for existing keys
|
||||
if _, err := os.Stat(info.KeysPath); err == nil {
|
||||
info.HasKeys = true
|
||||
}
|
||||
|
||||
// Check for existing config
|
||||
if _, err := os.Stat(info.ConfigPath); err == nil {
|
||||
info.HasConfig = true
|
||||
|
||||
// Parse existing config for fingerprint/wallet/nickname
|
||||
if file, err := os.Open(info.ConfigPath); err == nil {
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse Nickname
|
||||
if strings.HasPrefix(line, "Nickname ") {
|
||||
info.Nickname = strings.TrimPrefix(line, "Nickname ")
|
||||
}
|
||||
|
||||
// Parse ContactInfo for wallet (format: ... @anon:0x... or @anon: 0x...)
|
||||
if strings.HasPrefix(line, "ContactInfo ") {
|
||||
contact := strings.TrimPrefix(line, "ContactInfo ")
|
||||
// Extract wallet address from @anon: prefix (handle space after colon)
|
||||
if idx := strings.Index(contact, "@anon:"); idx != -1 {
|
||||
wallet := strings.TrimSpace(contact[idx+6:])
|
||||
info.Wallet = wallet
|
||||
}
|
||||
}
|
||||
|
||||
// Parse MyFamily (critical to preserve for multi-relay operators)
|
||||
if strings.HasPrefix(line, "MyFamily ") {
|
||||
info.MyFamily = strings.TrimPrefix(line, "MyFamily ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if anon service is running
|
||||
cmd := exec.Command("systemctl", "is-active", "--quiet", "anon")
|
||||
if cmd.Run() == nil {
|
||||
info.IsRunning = true
|
||||
}
|
||||
|
||||
// Try to get fingerprint from data directory (it's in /var/lib/anon/, not keys/)
|
||||
fingerprintFile := "/var/lib/anon/fingerprint"
|
||||
if data, err := os.ReadFile(fingerprintFile); err == nil {
|
||||
info.Fingerprint = strings.TrimSpace(string(data))
|
||||
}
|
||||
|
||||
// Return nil if no installation detected
|
||||
if !info.HasKeys && !info.HasConfig && !info.IsRunning {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// IsInstalled checks if the anon relay binary is installed
|
||||
func (ari *AnyoneRelayInstaller) IsInstalled() bool {
|
||||
// Check if anon binary exists
|
||||
if _, err := exec.LookPath("anon"); err == nil {
|
||||
return true
|
||||
}
|
||||
// Check common installation path
|
||||
if _, err := os.Stat("/usr/bin/anon"); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Install downloads and installs the Anyone relay using the official install script
|
||||
func (ari *AnyoneRelayInstaller) Install() error {
|
||||
fmt.Fprintf(ari.logWriter, " Installing Anyone relay...\n")
|
||||
|
||||
// Create required directories
|
||||
dirs := []string{
|
||||
"/etc/anon",
|
||||
"/var/lib/anon",
|
||||
"/var/log/anon",
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Download the official install script
|
||||
installScript := "/tmp/anon-install.sh"
|
||||
scriptURL := "https://raw.githubusercontent.com/anyone-protocol/anon-install/refs/heads/main/install.sh"
|
||||
|
||||
fmt.Fprintf(ari.logWriter, " Downloading install script...\n")
|
||||
if err := DownloadFile(scriptURL, installScript); err != nil {
|
||||
return fmt.Errorf("failed to download install script: %w", err)
|
||||
}
|
||||
|
||||
// Make script executable
|
||||
if err := os.Chmod(installScript, 0755); err != nil {
|
||||
return fmt.Errorf("failed to chmod install script: %w", err)
|
||||
}
|
||||
|
||||
// The official script is interactive, so we need to provide answers via stdin
|
||||
// or install the package directly
|
||||
fmt.Fprintf(ari.logWriter, " Installing anon package...\n")
|
||||
|
||||
// Add the Anyone repository and install the package directly
|
||||
// This is more reliable than running the interactive script
|
||||
if err := ari.addAnyoneRepository(); err != nil {
|
||||
return fmt.Errorf("failed to add Anyone repository: %w", err)
|
||||
}
|
||||
|
||||
// Install the anon package
|
||||
cmd := exec.Command("apt-get", "install", "-y", "anon")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to install anon package: %w\n%s", err, string(output))
|
||||
}
|
||||
|
||||
// Clean up
|
||||
os.Remove(installScript)
|
||||
|
||||
fmt.Fprintf(ari.logWriter, " ✓ Anyone relay binary installed\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// addAnyoneRepository adds the Anyone apt repository
|
||||
func (ari *AnyoneRelayInstaller) addAnyoneRepository() error {
|
||||
// Add GPG key using wget (as per official install script)
|
||||
fmt.Fprintf(ari.logWriter, " Adding Anyone repository key...\n")
|
||||
|
||||
// Download and add the GPG key using the official method
|
||||
keyPath := "/etc/apt/trusted.gpg.d/anon.asc"
|
||||
cmd := exec.Command("bash", "-c", "wget -qO- https://deb.en.anyone.tech/anon.asc | tee "+keyPath)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to download GPG key: %w\n%s", err, string(output))
|
||||
}
|
||||
|
||||
// Add repository
|
||||
fmt.Fprintf(ari.logWriter, " Adding Anyone repository...\n")
|
||||
|
||||
// Determine distribution codename
|
||||
codename := "stable"
|
||||
if data, err := exec.Command("lsb_release", "-cs").Output(); err == nil {
|
||||
codename = strings.TrimSpace(string(data))
|
||||
}
|
||||
|
||||
// Create sources.list entry using the official format: anon-live-$VERSION_CODENAME
|
||||
repoLine := fmt.Sprintf("deb [signed-by=%s] https://deb.en.anyone.tech anon-live-%s main\n", keyPath, codename)
|
||||
if err := os.WriteFile("/etc/apt/sources.list.d/anon.list", []byte(repoLine), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write repository file: %w", err)
|
||||
}
|
||||
|
||||
// Update apt
|
||||
cmd = exec.Command("apt-get", "update", "--yes")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
fmt.Fprintf(ari.logWriter, " ⚠️ Warning: apt update failed: %s\n", string(output))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Configure generates the anonrc configuration file
|
||||
func (ari *AnyoneRelayInstaller) Configure() error {
|
||||
fmt.Fprintf(ari.logWriter, " Configuring Anyone relay...\n")
|
||||
|
||||
configPath := "/etc/anon/anonrc"
|
||||
|
||||
// Backup existing config if it exists
|
||||
if _, err := os.Stat(configPath); err == nil {
|
||||
backupPath := configPath + ".bak"
|
||||
if err := exec.Command("cp", configPath, backupPath).Run(); err != nil {
|
||||
fmt.Fprintf(ari.logWriter, " ⚠️ Warning: failed to backup existing config: %v\n", err)
|
||||
} else {
|
||||
fmt.Fprintf(ari.logWriter, " Backed up existing config to %s\n", backupPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate configuration
|
||||
config := ari.generateAnonrc()
|
||||
|
||||
// Write configuration
|
||||
if err := os.WriteFile(configPath, []byte(config), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write anonrc: %w", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(ari.logWriter, " ✓ Anyone relay configured\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateAnonrc creates the anonrc configuration content
|
||||
func (ari *AnyoneRelayInstaller) generateAnonrc() string {
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString("# Anyone Relay Configuration (Managed by Orama Network)\n")
|
||||
sb.WriteString("# Generated automatically - manual edits may be overwritten\n\n")
|
||||
|
||||
// Nickname
|
||||
sb.WriteString(fmt.Sprintf("Nickname %s\n", ari.config.Nickname))
|
||||
|
||||
// Contact info with wallet
|
||||
if ari.config.Wallet != "" {
|
||||
sb.WriteString(fmt.Sprintf("ContactInfo %s @anon:%s\n", ari.config.Contact, ari.config.Wallet))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("ContactInfo %s\n", ari.config.Contact))
|
||||
}
|
||||
|
||||
sb.WriteString("\n")
|
||||
|
||||
// ORPort
|
||||
sb.WriteString(fmt.Sprintf("ORPort %d\n", ari.config.ORPort))
|
||||
|
||||
// SOCKS port for local use
|
||||
sb.WriteString("SocksPort 9050\n")
|
||||
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Exit relay configuration
|
||||
if ari.config.ExitRelay {
|
||||
sb.WriteString("ExitRelay 1\n")
|
||||
sb.WriteString("# Exit policy - allow common ports\n")
|
||||
sb.WriteString("ExitPolicy accept *:80\n")
|
||||
sb.WriteString("ExitPolicy accept *:443\n")
|
||||
sb.WriteString("ExitPolicy reject *:*\n")
|
||||
} else {
|
||||
sb.WriteString("ExitRelay 0\n")
|
||||
sb.WriteString("ExitPolicy reject *:*\n")
|
||||
}
|
||||
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Logging
|
||||
sb.WriteString("Log notice file /var/log/anon/notices.log\n")
|
||||
|
||||
// Data directory
|
||||
sb.WriteString("DataDirectory /var/lib/anon\n")
|
||||
|
||||
// Control port for monitoring
|
||||
sb.WriteString("ControlPort 9051\n")
|
||||
|
||||
// MyFamily for multi-relay operators (preserve from existing config)
|
||||
if ari.config.MyFamily != "" {
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf("MyFamily %s\n", ari.config.MyFamily))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// MigrateExistingInstallation migrates an existing Anyone installation into Orama Network
|
||||
func (ari *AnyoneRelayInstaller) MigrateExistingInstallation(existing *ExistingAnyoneInfo, backupDir string) error {
|
||||
fmt.Fprintf(ari.logWriter, " Migrating existing Anyone installation...\n")
|
||||
|
||||
// Create backup directory
|
||||
backupAnonDir := filepath.Join(backupDir, "anon-backup")
|
||||
if err := os.MkdirAll(backupAnonDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create backup directory: %w", err)
|
||||
}
|
||||
|
||||
// Stop existing anon service if running
|
||||
if existing.IsRunning {
|
||||
fmt.Fprintf(ari.logWriter, " Stopping existing anon service...\n")
|
||||
exec.Command("systemctl", "stop", "anon").Run()
|
||||
}
|
||||
|
||||
// Backup keys
|
||||
if existing.HasKeys {
|
||||
fmt.Fprintf(ari.logWriter, " Backing up keys...\n")
|
||||
keysBackup := filepath.Join(backupAnonDir, "keys")
|
||||
if err := exec.Command("cp", "-r", existing.KeysPath, keysBackup).Run(); err != nil {
|
||||
return fmt.Errorf("failed to backup keys: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Backup config
|
||||
if existing.HasConfig {
|
||||
fmt.Fprintf(ari.logWriter, " Backing up config...\n")
|
||||
configBackup := filepath.Join(backupAnonDir, "anonrc")
|
||||
if err := exec.Command("cp", existing.ConfigPath, configBackup).Run(); err != nil {
|
||||
return fmt.Errorf("failed to backup config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve nickname from existing installation if not provided
|
||||
if ari.config.Nickname == "" && existing.Nickname != "" {
|
||||
fmt.Fprintf(ari.logWriter, " Using existing nickname: %s\n", existing.Nickname)
|
||||
ari.config.Nickname = existing.Nickname
|
||||
}
|
||||
|
||||
// Preserve wallet from existing installation if not provided
|
||||
if ari.config.Wallet == "" && existing.Wallet != "" {
|
||||
fmt.Fprintf(ari.logWriter, " Using existing wallet: %s\n", existing.Wallet)
|
||||
ari.config.Wallet = existing.Wallet
|
||||
}
|
||||
|
||||
// Preserve MyFamily from existing installation (critical for multi-relay operators)
|
||||
if existing.MyFamily != "" {
|
||||
fmt.Fprintf(ari.logWriter, " Preserving MyFamily configuration (%d relays)\n", len(strings.Split(existing.MyFamily, ",")))
|
||||
ari.config.MyFamily = existing.MyFamily
|
||||
}
|
||||
|
||||
fmt.Fprintf(ari.logWriter, " ✓ Backup created at %s\n", backupAnonDir)
|
||||
fmt.Fprintf(ari.logWriter, " ✓ Migration complete - keys and fingerprint preserved\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateNickname validates the relay nickname (1-19 alphanumeric chars)
|
||||
func ValidateNickname(nickname string) error {
|
||||
if len(nickname) < 1 || len(nickname) > 19 {
|
||||
return fmt.Errorf("nickname must be 1-19 characters")
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(nickname) {
|
||||
return fmt.Errorf("nickname must be alphanumeric only")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateWallet validates an Ethereum wallet address
|
||||
func ValidateWallet(wallet string) error {
|
||||
if !regexp.MustCompile(`^0x[a-fA-F0-9]{40}$`).MatchString(wallet) {
|
||||
return fmt.Errorf("invalid Ethereum wallet address (must be 0x followed by 40 hex characters)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -8,8 +8,22 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/DeBrosOfficial/network/pkg/environments/production/installers"
|
||||
)
|
||||
|
||||
// AnyoneRelayConfig holds configuration for Anyone relay mode
|
||||
type AnyoneRelayConfig struct {
|
||||
Enabled bool // Whether to run as relay operator
|
||||
Exit bool // Whether to run as exit relay
|
||||
Migrate bool // Whether to migrate existing installation
|
||||
Nickname string // Relay nickname (1-19 alphanumeric)
|
||||
Contact string // Contact info (email or @telegram)
|
||||
Wallet string // Ethereum wallet for rewards
|
||||
ORPort int // ORPort for relay (default 9001)
|
||||
MyFamily string // Comma-separated fingerprints of other relays (for multi-relay operators)
|
||||
}
|
||||
|
||||
// ProductionSetup orchestrates the entire production deployment
|
||||
type ProductionSetup struct {
|
||||
osInfo *OSInfo
|
||||
@ -21,6 +35,7 @@ type ProductionSetup struct {
|
||||
skipOptionalDeps bool
|
||||
skipResourceChecks bool
|
||||
isNameserver bool // Whether this node is a nameserver (runs CoreDNS + Caddy)
|
||||
anyoneRelayConfig *AnyoneRelayConfig // Configuration for Anyone relay mode
|
||||
privChecker *PrivilegeChecker
|
||||
osDetector *OSDetector
|
||||
archDetector *ArchitectureDetector
|
||||
@ -123,6 +138,16 @@ func (ps *ProductionSetup) IsNameserver() bool {
|
||||
return ps.isNameserver
|
||||
}
|
||||
|
||||
// SetAnyoneRelayConfig sets the Anyone relay configuration
|
||||
func (ps *ProductionSetup) SetAnyoneRelayConfig(config *AnyoneRelayConfig) {
|
||||
ps.anyoneRelayConfig = config
|
||||
}
|
||||
|
||||
// IsAnyoneRelay returns whether this node is configured as an Anyone relay operator
|
||||
func (ps *ProductionSetup) IsAnyoneRelay() bool {
|
||||
return ps.anyoneRelayConfig != nil && ps.anyoneRelayConfig.Enabled
|
||||
}
|
||||
|
||||
// Phase1CheckPrerequisites performs initial environment validation
|
||||
func (ps *ProductionSetup) Phase1CheckPrerequisites() error {
|
||||
ps.logf("Phase 1: Checking prerequisites...")
|
||||
@ -275,9 +300,47 @@ func (ps *ProductionSetup) Phase2bInstallBinaries() error {
|
||||
ps.logf(" ⚠️ Olric install warning: %v", err)
|
||||
}
|
||||
|
||||
// Install anyone-client for SOCKS5 proxy
|
||||
if err := ps.binaryInstaller.InstallAnyoneClient(); err != nil {
|
||||
ps.logf(" ⚠️ anyone-client install warning: %v", err)
|
||||
// Install Anyone (client or relay based on configuration)
|
||||
if ps.IsAnyoneRelay() {
|
||||
ps.logf(" Installing Anyone relay (operator mode)...")
|
||||
relayConfig := installers.AnyoneRelayConfig{
|
||||
Nickname: ps.anyoneRelayConfig.Nickname,
|
||||
Contact: ps.anyoneRelayConfig.Contact,
|
||||
Wallet: ps.anyoneRelayConfig.Wallet,
|
||||
ORPort: ps.anyoneRelayConfig.ORPort,
|
||||
ExitRelay: ps.anyoneRelayConfig.Exit,
|
||||
Migrate: ps.anyoneRelayConfig.Migrate,
|
||||
MyFamily: ps.anyoneRelayConfig.MyFamily,
|
||||
}
|
||||
relayInstaller := installers.NewAnyoneRelayInstaller(ps.arch, ps.logWriter, relayConfig)
|
||||
|
||||
// Check for existing installation if migration is requested
|
||||
if relayConfig.Migrate {
|
||||
existing, err := installers.DetectExistingAnyoneInstallation()
|
||||
if err != nil {
|
||||
ps.logf(" ⚠️ Failed to detect existing installation: %v", err)
|
||||
} else if existing != nil {
|
||||
backupDir := filepath.Join(ps.oramaDir, "backups")
|
||||
if err := relayInstaller.MigrateExistingInstallation(existing, backupDir); err != nil {
|
||||
ps.logf(" ⚠️ Migration warning: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Install the relay
|
||||
if err := relayInstaller.Install(); err != nil {
|
||||
ps.logf(" ⚠️ Anyone relay install warning: %v", err)
|
||||
}
|
||||
|
||||
// Configure the relay
|
||||
if err := relayInstaller.Configure(); err != nil {
|
||||
ps.logf(" ⚠️ Anyone relay config warning: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Install anyone-client for SOCKS5 proxy (default client mode)
|
||||
if err := ps.binaryInstaller.InstallAnyoneClient(); err != nil {
|
||||
ps.logf(" ⚠️ anyone-client install warning: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Install DeBros binaries (must be done before CoreDNS since we need the RQLite plugin source)
|
||||
@ -551,12 +614,20 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error {
|
||||
}
|
||||
ps.logf(" ✓ Node service created: debros-node.service (with embedded gateway)")
|
||||
|
||||
// Anyone Client service (SOCKS5 proxy)
|
||||
anyoneUnit := ps.serviceGenerator.GenerateAnyoneClientService()
|
||||
if err := ps.serviceController.WriteServiceUnit("debros-anyone-client.service", anyoneUnit); err != nil {
|
||||
return fmt.Errorf("failed to write Anyone Client service: %w", err)
|
||||
// Anyone service (Client or Relay based on configuration)
|
||||
if ps.IsAnyoneRelay() {
|
||||
anyoneUnit := ps.serviceGenerator.GenerateAnyoneRelayService()
|
||||
if err := ps.serviceController.WriteServiceUnit("debros-anyone-relay.service", anyoneUnit); err != nil {
|
||||
return fmt.Errorf("failed to write Anyone Relay service: %w", err)
|
||||
}
|
||||
ps.logf(" ✓ Anyone Relay service created (operator mode, ORPort: %d)", ps.anyoneRelayConfig.ORPort)
|
||||
} else {
|
||||
anyoneUnit := ps.serviceGenerator.GenerateAnyoneClientService()
|
||||
if err := ps.serviceController.WriteServiceUnit("debros-anyone-client.service", anyoneUnit); err != nil {
|
||||
return fmt.Errorf("failed to write Anyone Client service: %w", err)
|
||||
}
|
||||
ps.logf(" ✓ Anyone Client service created")
|
||||
}
|
||||
ps.logf(" ✓ Anyone Client service created")
|
||||
|
||||
// CoreDNS and Caddy services (only for nameserver nodes)
|
||||
if ps.isNameserver {
|
||||
@ -595,7 +666,14 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error {
|
||||
// Enable services (unified names - no bootstrap/node distinction)
|
||||
// Note: debros-gateway.service is no longer needed - each node has an embedded gateway
|
||||
// Note: debros-rqlite.service is NOT created - RQLite is managed by each node internally
|
||||
services := []string{"debros-ipfs.service", "debros-ipfs-cluster.service", "debros-olric.service", "debros-node.service", "debros-anyone-client.service"}
|
||||
services := []string{"debros-ipfs.service", "debros-ipfs-cluster.service", "debros-olric.service", "debros-node.service"}
|
||||
|
||||
// Add appropriate Anyone service based on mode
|
||||
if ps.IsAnyoneRelay() {
|
||||
services = append(services, "debros-anyone-relay.service")
|
||||
} else {
|
||||
services = append(services, "debros-anyone-client.service")
|
||||
}
|
||||
|
||||
// Add CoreDNS and Caddy only for nameserver nodes
|
||||
if ps.isNameserver {
|
||||
@ -617,15 +695,30 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(enableHTTPS bool) error {
|
||||
// Start services in dependency order
|
||||
ps.logf(" Starting services...")
|
||||
|
||||
// Start infrastructure first (IPFS, Olric, Anyone Client) - RQLite is managed internally by each node
|
||||
// Start infrastructure first (IPFS, Olric, Anyone) - RQLite is managed internally by each node
|
||||
infraServices := []string{"debros-ipfs.service", "debros-olric.service"}
|
||||
|
||||
// Check if port 9050 is already in use (e.g., another anyone-client or similar service)
|
||||
if ps.portChecker.IsPortInUse(9050) {
|
||||
ps.logf(" ℹ️ Port 9050 is already in use (anyone-client or similar service running)")
|
||||
ps.logf(" ℹ️ Skipping debros-anyone-client startup - using existing service")
|
||||
|
||||
// Add appropriate Anyone service based on mode
|
||||
if ps.IsAnyoneRelay() {
|
||||
// For relay mode, check if ORPort is already in use
|
||||
orPort := 9001
|
||||
if ps.anyoneRelayConfig != nil && ps.anyoneRelayConfig.ORPort > 0 {
|
||||
orPort = ps.anyoneRelayConfig.ORPort
|
||||
}
|
||||
if ps.portChecker.IsPortInUse(orPort) {
|
||||
ps.logf(" ℹ️ ORPort %d is already in use (existing anon relay running)", orPort)
|
||||
ps.logf(" ℹ️ Skipping debros-anyone-relay startup - using existing service")
|
||||
} else {
|
||||
infraServices = append(infraServices, "debros-anyone-relay.service")
|
||||
}
|
||||
} else {
|
||||
infraServices = append(infraServices, "debros-anyone-client.service")
|
||||
// For client mode, check if SOCKS port 9050 is already in use
|
||||
if ps.portChecker.IsPortInUse(9050) {
|
||||
ps.logf(" ℹ️ Port 9050 is already in use (anyone-client or similar service running)")
|
||||
ps.logf(" ℹ️ Skipping debros-anyone-client startup - using existing service")
|
||||
} else {
|
||||
infraServices = append(infraServices, "debros-anyone-client.service")
|
||||
}
|
||||
}
|
||||
|
||||
for _, svc := range infraServices {
|
||||
@ -720,11 +813,27 @@ func (ps *ProductionSetup) LogSetupComplete(peerID string) {
|
||||
ps.logf(" %s/logs/olric.log", ps.oramaDir)
|
||||
ps.logf(" %s/logs/node.log", ps.oramaDir)
|
||||
ps.logf(" %s/logs/gateway.log", ps.oramaDir)
|
||||
ps.logf(" %s/logs/anyone-client.log", ps.oramaDir)
|
||||
ps.logf("\nStart All Services:")
|
||||
ps.logf(" systemctl start debros-ipfs debros-ipfs-cluster debros-olric debros-anyone-client debros-node")
|
||||
|
||||
// Anyone mode-specific logs and commands
|
||||
if ps.IsAnyoneRelay() {
|
||||
ps.logf(" /var/log/anon/notices.log (Anyone Relay)")
|
||||
ps.logf("\nStart All Services:")
|
||||
ps.logf(" systemctl start debros-ipfs debros-ipfs-cluster debros-olric debros-anyone-relay debros-node")
|
||||
ps.logf("\nAnyone Relay Operator:")
|
||||
ps.logf(" ORPort: %d", ps.anyoneRelayConfig.ORPort)
|
||||
ps.logf(" Wallet: %s", ps.anyoneRelayConfig.Wallet)
|
||||
ps.logf(" Config: /etc/anon/anonrc")
|
||||
ps.logf(" Register at: https://dashboard.anyone.io")
|
||||
ps.logf(" IMPORTANT: You need 100 $ANYONE tokens in your wallet to receive rewards")
|
||||
} else {
|
||||
ps.logf(" %s/logs/anyone-client.log", ps.oramaDir)
|
||||
ps.logf("\nStart All Services:")
|
||||
ps.logf(" systemctl start debros-ipfs debros-ipfs-cluster debros-olric debros-anyone-client debros-node")
|
||||
ps.logf("\nAnyone Client:")
|
||||
ps.logf(" # SOCKS5 proxy on localhost:9050")
|
||||
}
|
||||
|
||||
ps.logf("\nVerify Installation:")
|
||||
ps.logf(" curl http://localhost:6001/health")
|
||||
ps.logf(" curl http://localhost:5001/status")
|
||||
ps.logf(" # Anyone Client SOCKS5 proxy on localhost:9050\n")
|
||||
ps.logf(" curl http://localhost:5001/status\n")
|
||||
}
|
||||
|
||||
@ -324,6 +324,36 @@ WantedBy=multi-user.target
|
||||
`, ssg.oramaHome, logFile, ssg.oramaDir)
|
||||
}
|
||||
|
||||
// GenerateAnyoneRelayService generates the Anyone Relay operator systemd unit
|
||||
// Uses debian-anon user created by the anon apt package
|
||||
func (ssg *SystemdServiceGenerator) GenerateAnyoneRelayService() string {
|
||||
return `[Unit]
|
||||
Description=Anyone Relay (Orama Network)
|
||||
Documentation=https://docs.anyone.io
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=debian-anon
|
||||
Group=debian-anon
|
||||
ExecStart=/usr/bin/anon --agree-to-terms
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
SyslogIdentifier=anon-relay
|
||||
|
||||
# Security hardening
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
PrivateTmp=yes
|
||||
ReadWritePaths=/var/lib/anon /var/log/anon /etc/anon
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`
|
||||
}
|
||||
|
||||
// GenerateCoreDNSService generates the CoreDNS systemd unit
|
||||
func (ssg *SystemdServiceGenerator) GenerateCoreDNSService() string {
|
||||
return `[Unit]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user