Connect WSL2 SQL Server localhost instance from Windows 10 - sql-server

I had setup a WSL2 Ubuntu. Now I am running a local SQL Server instance on the 1401 port using Docker.
Container port:
0.0.0.0:1401->1433/tcp
I would like to connect this instance from SSMS but I am getting following error:
Server name: localhost, 1401
Error:
Cannot connect to localhost,1401.
A network-related or instance-specific error occurred while
establishing a connection to SQL Server.
The server was not found or was not accessible. Verify that the
instance name is correct and that SQL Server is configured to allow
remote connections.
(provider: TCP Provider, error: 0 - The wait operation timed out.)
(Microsoft SQL Server, Error: 258)
[Solution]
I am able to connect it via the WSL2 IP. I run "hostname -I" command in WSL2 and use the same IP in SSMS. And, I am able to make a connection

First question -- Is there a VPN running/connected in Windows? If so, ignore the rest of this and suspect that first. Make sure the VPN is not running, stop Docker, issue a wsl --shutdown, restart and try again.
Assuming that's not the problem ...
Normally, WSL2 provides a feature known as "localhost forwarding" which allows services/apps on Windows to communicate with the virtualized WSL2 IP using localhost. It essentially takes any localhost traffic that isn't directed to a port bound under Windows and forwards it to the Hyper-V virtual network for WSL2.
All WSL2 instances (including the Docker instance) share the same WSL2 network interface as they are all running in the same virtual machine/kernel.
So you seem to be doing the right thing in attempting to connect to localhost from SSMS.
But ... sometimes that localhost forwarding breaks. There are two common (related) scenarios that can cause this (and perhaps others):
Hibernation of the Windows host
Having Windows Fast Startup enabled in Power Manager
First check to make sure you can access 1401 from within WSL2:
nc -zv localhost 1401
^^^ assumes netcat is installed, which it is by default in the WSL2 Ubuntu distribution. For other distributions, install it or check connectivity via other methods.
If that doesn't succeed, then I'd suspect some configuration issue in SQL Server.
If that does succeed, then run the same test from the Windows host in PowerShell:
Test-NetConnection -ComputerName "localhost" -Port 1401
If that doesn't succeed, then I'd suspect a localhost forwarding issue.
Side note: I'm assuming you are running Docker Desktop, but if you are just running Docker Engine in a WSL2 instance, that's no problem. Just ignore the Docker Desktop instructions below.
First, check if you have a /etc/wsl.conf in any of your running WSL2 instances that mention disabling localhostForwarding. I'm assuming no, since that is not the default. However, if you happen to, make sure you set these to true.
Stop all WSL2 services, instances, shells, apps, etc. (including Docker Desktop)
From PowerShell:
wsl --shutdown
Then restart Docker Desktop and/or your container and try again

If localhost doesn’t work, try use [::1] in the server name. In WSL2, port 1433 is using IP/TCPv6, SSMS some times is not able to resolve localhost to loopback IP [::1].
Source: https://jayfuconsulting.wordpress.com/2020/11/14/sql-server-2019-docker-wsl-2/

One last thing which you could try is to modify the windows host file. I almost tried all the steps mentioned over different link, but all goes in vain. Then I opened the host file which could be accessed using
C:\Windows\System32\Drivers\Etc
Open the host file and uncomment(remove # sign) from the localhost name resolution section

Related

Can't reach docker-hosted SQL server from web app docker on same host

On the same virutal machine (remote, ubuntu), I have
An SQL Server running in a Docker
An .NET Core 2.2 (IdentityServer) application running in a docker
An instance of jwilder.nginx-proxy serving as a reverse-proxy for every web application on the machine
A multitude of other .NET Core apps
I am able to connect to all of my websites using both machine IP + port and domain name, which means the reverse proxy works as expected and the dockers are well-configured
I am able to connect to the SQL Server using SSMS from my local machine, which means that the SQL Server docker properly forwards the TCP connection on port 1433
The IdentityServer .NET Core 2 web application is able to connect to the SQL Server when run on my local machine.
The remote-docker IdentityServer application can't reach the SQL Server instance with the following error (shortened for clarity - removed stack trace)
System.Data.SqlClient.SqlException (0x80131904):
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: TCP Provider, error: 40 - Could not open a connection to SQL Server) at [...]
I know that the SQL server is running and reachable from the internet, and I know that the application's code is not at fault because I tested both.
So I deduced it had to be the IdentityServer docker that was blocking the connexion. So I tried:
Using the --expose 20 command on the IdentityServer docker
Opening mapping the port 20 inside the container to some port outside -p 45264:20 in addition to the already exposed port 80
I originally worked on using the port 1433 on both sides of the mapping but since it didn't work I tried using an other port on the outside (20). Didn't change anything
Here is the connexion string used by the IdentityServer (sensitive data hidden):
Data Source=***.***.***.***,20;Initial Catalog=Identity;Persist Security Info=True;User ID=**;Password=******************
Why can't my IdentityServer docker reach the SQL Server docker while the SQL Server itself is perfectly reachable? How can I make this setup work?
When wrapping SQL server into Docker, the first thing to anticipate is the way you connect. SQL Server prefers named pipes and you have to explicitly set mode to tcp.
If connection is done locally, don't use localhost, change it to 127.0.0.1. Also writing explicit tcp: prefix may help, like this: Server=tcp:x.y.z.q,1433
As I understood you run Sql Server and IdentityServer (which has connection problem) in separate docker containers.
If this is so then referring to localhost (i.e. 127.0.0.1) is not correct. Because in this case IdentityServer tries to connect to itself. This would work if the IdentityServer have run on the host machine, since you forward SQL server port to it. But in your case, you should connect to the SQL server container IP instead.
Considering all above I see three options for you to solve this:
You can get ip address of SQL Server container by running docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <sql_container_name_or_id>
Run SQL container with static IP via docker run --ip <static_ip_value> <sql_container_name_or_id> and then use static ip you have specified in connection string.
Run SQL container with specified host name via docker run --hostname <sql_host_name> <sql_container_name_or_id> and then use specified hostname in the connection string.
It is up to you which way to go.
Use tcp, 127.0.0.1 and host port to connect. Mention in the identity server docker settings that it depends on sql database server container. Like this,
identityservice:
...
depends_on:
- sqldataservice
This way the database container will be made available first.
"ConnectionString": "Server=tcp:127.0.0.1,8433;Database=dbname;User Id=sa;Password=abc#1234;"
I ended up giving up on getting this to work using a single host, so I simply decided to have the SQL Server run in a separate machine.

SQL Server TCP/IP times out

I have to connect to a fresh SQL Server Express 2017 on a machine not part of my domain. I have configured
Mixed Mode Installation with sa with password
SSMS -> Server -> Properties -> Connections -> Allow remote connections
SQL Configuration Manager -> Instance "EXPRESS2017" -> TCP/IP: Enable and Active and Port 1438
Restarted the "SQL Server (EXPRESS2017)" service.
I now tried to access from a remote computer, and got a timeout. I then tried to connect from the local SSMS, which works without special settings, but when under options, forced "Protocol: TCP/IP" is set, with the same credentials as before, I also got a timeout.
So am I right that I can rule out the firewall or problems finding the instance, and everything points towards a configuration issue in TCP/IP protocol, or did I overlook some setting?
EDIT: I have disabled Windows firewall, and no other firewall is installed on the computer. I have restarted the computer. I also found this article about PortQry and had a check - locally:
C:\Users\Administrator\Downloads>PortQry.exe -n 172.17.41.124 -p UDP -e 1434
Querying target system called:
172.17.41.124
Attempting to resolve IP address to a name...
IP address resolved to WIN-AECL8CJVS7E.test.local
querying...
UDP port 1434 (ms-sql-m service): NOT LISTENING
EDIT: I have run NETSTAT and it seems no port in the 14xx range is open at all, although the SQL Server Browser service is running. I must be missing something there...
You did not show your connection string, but I suppose you use your instance name here.
In order to connect to SQL Server the network library has to know 2 things: IP address and a port. Your instance is named and uses non-default port 1438.
So your connection string should use 172.17.41.124,1438 as server name, or, alternatively, you can use instance name like this: 172.17.41.124\EXPRESS2017 but SQL Server Browser should run.

How does .NET Core on Linux determine what port a SQL Server instance listens on?

I have an ASP.NET Core 1.1 Web API which runs in a Docker container on Ubuntu and connects out to a SQL Server database (SQL Server 2012 SP3) on a Windows server. This works in 3 out of 4 of out environments, but in one environment it cannot connect to the SQL Server and I am trying to troubleshoot it.
The error is:
Unhandled Exception: System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 25 - Connection string is not valid)
The SQL Server has an instance name: SQLSERVER1\APPS. From the Linux server I can ping the server SQLSERVER1 and telnet to SQLSERVER1 1372 (1372 is the port for the APPS instance: so network connectivity is there.
The only space I can see for the problem to occur is how .NET Core translates the instance name to a port number. Does anyone know how this is done and whether it is configurable on the client machine?
Remote named instance listening port discovery relies SQL Server Browser Service and protocol. As you cannot leverage this for your Linux docker image, I suggest you connect by explicitly specifying the port and omitting the instance name: "server=tcp:SQLSERVER1,1372;database=...;...":
The name or network address of the instance of SQL Server to which to connect. The port number can be specified after the server name: server=tcp:servername, portnumber
BTW if you live the instance name it should make no difference whatsoever after you explicitly specify the port.
PS. After reading again the question, the issue is related but different cause. Normally the Linux container can discover the Windows SQL Server, as the Browser service is probably up and running (proof that 3 envs. it works). In the 4th environment it means something blocks the discovery. Either the Browser service is stopped, or the browser discovery protocol listening port is blocked in the FW (UDP 1433), or perhaps the UDP packet (or the response!) is lost somewhere between the container and the server. You can investigate and find the root cause, but, you can also just ignore the problem and work around the issue by... specifying the port explicitly, just as I showed.

What would prevent code running in a Docker container from connecting to a database on a separate server?

I have a .NET Core 1.1 app running in a Docker container on Ubuntu 14.04, and it fails to connect to the SQL Server database running on a separate server.
The error is:
Unhandled Exception: System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 25 - Connection string is not valid)
I have deployed the same image with the same command line on another Ubuntu 14.04 server, and it connects fine.
A console app running on the problem server (outside of Docker) can connect with the same connection string.
As far as I can see from the documentation, an app running in a container has access to the external network by default, so what could be blocking this connection?
an app running in a container has access to the external network by default
It could have access only if a valid IP address is assigned to the container. Sometimes the IP which Docker choose for the container can conflict with external networks.
By default, containers run in bridge network, so look at it:
docker network inspect bridge
Find the container and check its IP.
To resolve conflicts, it is possible to customize bridge network and set bip parameter to change the network's IP range (config file location depends on host's OS):
"bip": "192.168.1.5/24"
Or create a new docker network.
Or experiment with net=host option: docker run network settings
Does this help?
Connect to SQL Server database from a docker container
Also, Googling this "docker connect to sql server database" seems to return a lot of helpful results.

Connect to SQL Server Developer from ASP.NET Core app running in Docker for Windows

I'm trying to connect to my SQL Server Developer edition on my local Windows 10 Pro machine from a docker image created using Visual Studio Tools for Docker Desktop for Windows. I've followed the tutorial here. Which helped me make sure that SQL Server is functional and exposed to the outside world.
My preference would be to somehow start docker with NET=HOST and just use . to access my DB. But, I'm not sure how to do that and I'm not sure if that even works on Windows.
Now I can't seem to get the connection right to actually connect to SQL. I've tried these:
Server={MyIPv4Address}:434;Database=MyDB;
MultipleActiveResultSets=true;User
Id=DeveloperLocalHost;Password=MyAwesomePassword
Server={MyIPv4Address};Database=MyDB;
MultipleActiveResultSets=true;User
Id=DeveloperLocalHost;Password=MyAwesomePassword
Server=.;Database=MyDB;
MultipleActiveResultSets=true;User
Id=DeveloperLocalHost;Password=MyAwesomePassword
I've tried many others from tutorials I have looked at online but don't remember them all. I'm a bit perplexed.
I would expect the second method (actual host IP and default 1433 port) to work as long as your SQL instance is configured to allow remote connections. Run this PS command from your container to verify port connectivity:
echo ((new-object Net.Sockets.TcpClient).Client.Connect("MyIPv4Address", "1433")) "connection successful"
Once you verify connectivity, you should be able to start the container with an environment variable and use that for your connection.

Resources