@@ -265,6 +265,7 @@ func runServe(cmd *cobra.Command, args []string) error {
265265 // Apply memory configuration FIRST (before heavy allocations)
266266 // First, try to load from config file, then fall back to environment variables
267267 var cfg * config.Config
268+ loadedConfigFile := false
268269 explicitConfigPath , _ := cmd .Flags ().GetString ("config" ) // persistent
269270 configPath := strings .TrimSpace (explicitConfigPath )
270271 if configPath == "" {
@@ -285,10 +286,15 @@ func runServe(cmd *cobra.Command, args []string) error {
285286 fmt .Printf ("⚠️ Warning: failed to load config from %s: %v\n " , configPath , err )
286287 cfg = config .LoadFromEnv ()
287288 } else {
289+ loadedConfigFile = true
288290 fmt .Printf ("📄 Loaded config from: %s\n " , configPath )
289291 }
290292 }
291293
294+ resolvedAddress := resolveBindAddress (cmd , cfg , address , loadedConfigFile )
295+ cfg .Server .HTTPAddress = resolvedAddress
296+ cfg .Server .BoltAddress = resolvedAddress
297+
292298 // YAML config file is the source of truth for embedding settings
293299 // Always use config file values if they are set (non-zero/non-empty)
294300 if cfg .Memory .EmbeddingDimensions > 0 {
@@ -558,7 +564,7 @@ func runServe(cmd *cobra.Command, args []string) error {
558564 // Create and start HTTP server
559565 serverConfig := server .DefaultConfig ()
560566 serverConfig .Port = httpPort
561- serverConfig .Address = address
567+ serverConfig .Address = resolvedAddress
562568 // MCP server configuration
563569 serverConfig .MCPEnabled = mcpEnabled
564570 // Pass embedding settings to server (from loaded config)
@@ -598,6 +604,7 @@ func runServe(cmd *cobra.Command, args []string) error {
598604
599605 // Create and start Bolt server for Neo4j driver compatibility
600606 boltConfig := bolt .DefaultConfig ()
607+ boltConfig .Host = resolvedAddress
601608 boltConfig .Port = boltPort
602609 boltConfig .LogQueries = logQueries
603610 boltConfig .ServerAnnouncement = cfg .Server .BoltServerAnnouncement
@@ -629,8 +636,8 @@ func runServe(cmd *cobra.Command, args []string) error {
629636 fmt .Println ("✅ NornicDB is ready!" )
630637 fmt .Println ()
631638 // Determine the display address for user-friendly output
632- displayAddr := address
633- if address == "0.0.0.0" {
639+ displayAddr := resolvedAddress
640+ if resolvedAddress == "0.0.0.0" || resolvedAddress == ":: " {
634641 displayAddr = "localhost" // 0.0.0.0 is all interfaces, show localhost for convenience
635642 }
636643 fmt .Println ("Endpoints:" )
@@ -688,6 +695,41 @@ func runServe(cmd *cobra.Command, args []string) error {
688695 return nil
689696}
690697
698+ func resolveBindAddress (cmd * cobra.Command , cfg * config.Config , cliAddress string , loadedConfigFile bool ) string {
699+ resolvedAddress := strings .TrimSpace (cliAddress )
700+ if cmd != nil && ! cmd .Flags ().Changed ("address" ) && cfg != nil {
701+ if loadedConfigFile && cfg .Server .HTTPAddress != "" {
702+ resolvedAddress = cfg .Server .HTTPAddress
703+ } else if loadedConfigFile && cfg .Server .BoltAddress != "" {
704+ resolvedAddress = cfg .Server .BoltAddress
705+ } else if hasExplicitProtocolBindEnv () {
706+ if cfg .Server .HTTPAddress != "" {
707+ resolvedAddress = cfg .Server .HTTPAddress
708+ } else if cfg .Server .BoltAddress != "" {
709+ resolvedAddress = cfg .Server .BoltAddress
710+ }
711+ }
712+ }
713+ if strings .TrimSpace (resolvedAddress ) == "" {
714+ return "127.0.0.1"
715+ }
716+ return strings .TrimSpace (resolvedAddress )
717+ }
718+
719+ func hasExplicitProtocolBindEnv () bool {
720+ for _ , envName := range []string {
721+ "NORNICDB_BOLT_ADDRESS" ,
722+ "NORNICDB_HTTP_ADDRESS" ,
723+ "NEO4J_dbms_connector_bolt_listen__address" ,
724+ "NEO4J_dbms_connector_http_listen__address" ,
725+ } {
726+ if strings .TrimSpace (os .Getenv (envName )) != "" {
727+ return true
728+ }
729+ }
730+ return false
731+ }
732+
691733func startStdioLogCompactor (maxKB int , interval time.Duration ) func () {
692734 if maxKB <= 0 {
693735 return func () {}
0 commit comments