I am trying to access mongodb through ssh tunneling

I’m trying to use atlas mongoDB using ssh tunnel with AWS EC2.
The language is Go.

I can guarantee that there will be no problems with EC2. It works when accessing with mongoDB compass.

However, implementing tunneling-connection directly in Go does not work well.

The tunneling code is:

import (
        ...
	"github.com/rgzr/sshtun"
	...
)
...
	sshTun := sshtun.New(27017, "EC2 IP", 27017)
	sshTun.SetUser("mongoproxy")
	sshTun.SetPassword("...")
	sshTun.SetLocalEndpoint(sshtun.NewTCPEndpoint("127.0.0.1", 27017))
	sshTun.SetRemoteEndpoint(sshtun.NewTCPEndpoint("...mongodb.net", 27017))

	sshTun.SetTunneledConnState(func(tun *sshtun.SSHTun, state *sshtun.TunneledConnState) {
		log.Printf("# TunneledConnState: %+v", state)
	})

	var connected atomic.Bool

	// We set a callback to know when the tunnel is ready
	sshTun.SetConnState(func(tun *sshtun.SSHTun, state sshtun.ConnState) {
		switch state {
		case sshtun.StateStarting:
			log.Printf("STATE is Starting")
		case sshtun.StateStarted:
			connected.Store(true)
			log.Printf("STATE is Started")
		case sshtun.StateStopped:
			connected.Store(false)
			log.Printf("STATE is Stopped")
		}
	})

	go func() {
		for {
			if err := sshTun.Start(context.Background()); err != nil {
				log.Printf("SSH tunnel error: %v", err)
				time.Sleep(time.Second * 10) 
			}
		}
	}()

	for !connected.Load() {
		time.Sleep(time.Second)
	}

       ...

The connection code is as follows:

func NewMongoClientWithTunneling(cfg *config.Config) MongoClient {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	dataSource := fmt.Sprintf(
		"mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority",
		cfg.Mongo.User,
		cfg.Mongo.Password,
		"127.0.0.1",
		cfg.Mongo.DBName,
	)

	c, err := mongo.Connect(ctx,
		options.
			Client().
			ApplyURI(dataSource).
			SetMinPoolSize(uint64(cfg.Mongo.Options.MinConnections)).
			SetMaxPoolSize(uint64(cfg.Mongo.Options.MaxConnections)).
			SetMaxConnIdleTime(10*time.Minute).
			SetMonitor(apmmongo.CommandMonitor()),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Check the connection
	if err := c.Ping(ctx, nil); err != nil {
		panic(fmt.Sprintf("Failed to connect to MongoDB: %v", err))
	}
...

When executing the above code, the following error occurs.
This is probably because the work done with srv cannot be done on the local host.

2023/08/31 18:37:01 error parsing uri: lookup _mongodb._tcp.127.0.0.1 on 168.126.63.1:53: no such host

I’m wondering what I did wrong and how compass handles this.

I need your help…

The test environment is M2 Pro ventura.

@myyrakle_N_A welcome and thanks for the question!

When using the mongodb+srv:// URI scheme, the Go driver expects to be able to look up a DNS SRV record named _mongodb._tcp.<hostname>. That won’t work when using an IP address, so using the mongodb+srv:// scheme is generally incompatible with using IP addresses.

Does the connection work if you use scheme mongodb:// instead?

For example:

dataSource := fmt.Sprintf(
	"mongodb://%s:%s@%s/%s?retryWrites=true&w=majority",
	cfg.Mongo.User,
	cfg.Mongo.Password,
	"127.0.0.1",
	cfg.Mongo.DBName,
)