How to close this ssh tunnel? [closed] - mysql

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I opened a ssh tunnel as described in this post: Zend_Db: How to connect to a MySQL database over SSH tunnel?
But now I don't know what I actually did. Does this command affect anything on the server?
And how do I close this tunnel, because now I can't use my local mysql properly.
I use OSX Lion and the server runs on Ubuntu 11.10.

Assuming you ran this command: ssh -f user#mysql-server.com -L 3306:mysql-server.com:3306 -N as described in the post you linked.
A breakdown of the command:
ssh: that's pretty self-explanatory. Invokes ssh.
-f: (From the man ssh page)
Requests ssh to go to background just before command execution.
This is useful if ssh is going to ask for passwords or
passphrases, but the user wants it in the background.
Essentially, send ssh to background once you've entered any passwords to establish the connection; it gives the shell prompt back to you at localhost rather than logging you in to remote-host.
user#mysql-server.com: the remote server you'd like to log into.
-L 3306:mysql-server.com:3306: This is the interesting bit. -L (from the man ssh page):
[bind_address:]port:host:hostport
Specifies that the given port on the local (client) host is to be
forwarded to the given host and port on the remote side.
So -L 3306:mysql-server.com:3306 binds the local port 3306 to the remote port 3306 on host mysql-server.com.
When you connect to local port 3306, the connection is forwarded over the secure channel to mysql-server.com. The remote host, mysql-server.com then connects to mysql-server.com on port 3306.
-N: don't execute a command. This is useful for "just forwarding ports" (quoting the man page).
Does this command affect anything on the server?
Yes, it establishes a connection between localhost and mysql-server.com on port 3306.
And how do I close this tunnel...
If you've used -f, you'll notice that the ssh process you've opened heads into the background. The nicer method of closing it is to run ps aux | grep 3306, find the pid of the ssh -f ... -L 3306:mysql-server.com:3306 -N, and kill <pid>. (Or maybe kill -9 <pid>; I forget if just kill works). That has the beautiful benefit of not killing all your other ssh connections; if you've got more than one, re-establishing them can be a slight ... pain.
... because now I can't use my local mysql properly.
This is because you've effectively "captured" the local mysql process and forwarded any traffic that attempts to connect to it, off to the remote mysql process. A much nicer solution would be to not use local port 3306 in the port-forward. Use something that's not used, like 33060. (Higher numbers are generally less used; it's pretty common to port-forward a combination like this: "2525->25", "8080->80", "33060->3306" or similar. Makes remembering slightly easier).
So, if you used ssh -f user#mysql-server.com -L 33060:mysql-server.com:3306 -N, you'd then point your Zend connect-to-mysql function to localhost on port 33060, which would connect to mysql-server.com on port 3306. You can obviously still connect to localhost on port 3306, so you can still use the local mysql server.

This will kill all ssh sessions that you have open from the terminal.
sudo killall ssh

Note: adding as answer since comments don't support code blocks.
In my opinion it is better to NOT use -f and instead just background the process as normal with &. That will give you the exact pid you need to kill:
ssh -N -L1234:other:1234 server &
pid=$!
echo "waiting a few seconds to establish tunnel..."
sleep 5
... do yer stuff... launch mysql workbench whatever
echo "killing ssh tunnel $pid"
kill $pid
Or better yet, just create this as a wrapper script:
# backend-tunnel <your cmd line, possibly 'bash'>
ssh -N -L1234:other:1234 server &
pid=$!
echo "waiting a few seconds to establish tunnel..."
sleep 5
"$#"
echo "killing ssh tunnel $pid"
kill $pid
backend-tunnel mysql-workbench
backend-tunnel bash

Related

Wait for SSH tunnel before continuing a script

I have a script that dumps data from a cloud foundry db, and it works in the following way:
cf ssh -L 33001:db.host:3306 --skip-remote-execution App &
TUNNEL_PID=$!
mysqldump --protocol TCP --port= 33001 ..... db_name > /tmp/my-db-dump.sql
kill $TUNNEL_PID
The problem is that mysqldump fails with
mysqldump: Got error: 2003: Can't connect to MySQL server on 'localhost' (61) when trying to connect
I expect that the problem is that the tunnel is not established yet. When I do sleep 5 before mysqldump, everything works. But I don't want to rely on random 5 seconds. Is it possible to wait for the tunnel to get started?
Can you run mysqldump via the ssh command, instead of opening a tunnel?
Mysqldump will write to its stdout, which will be transferred back to your client host via the ssh command.
ssh App "mysqldump db_name" > /tmp/my-db-dump.sql
Or you could even dump to a compressed file on the server, and then fetch the dump file with scp. That will help the transfer to go faster.
ssh App "mysqldump db_name | gzip -c > /tmp/my-db-dump.sql.gz"
scp App:/tmp/my-db-dump.sql.gz .
ssh App "rm /tmp/my-db-dump.sql.gz"
This is untested, but I hope it gives you some ideas to experiment with.

MySQL-Python code to query a MYSQL database through an SSH tunnel

I have access to a MySQL database through ssh,
Could someone direct me to a MySQL-python code that will let me do this?
I need to save my query results on my local WINDOWS computer,
Thanks,
You can use SSH port forwarding to do this.. in fact first google hit looks to walk you through this exact thing:
http://www.howtogeek.com/howto/ubuntu/access-your-mysql-server-remotely-over-ssh/
And since you're on windows, translate that to using PuTTY:
https://intranet.cs.hku.hk/csintranet/contents/technical/howto/putty-portforward.jsp
You'll then connect to localhost:3306 with your python script, SSH will forward that over to the other machine and you'll end up connecting to the remote mysql instance.
You need to open up an SSH Tunnel to your sql server and then you can run paramiko to connect locally to the port you are using locally. This is done quite easily in *nix systems and I am sure you can download ssh command line too for windows. Try putty or plink, see here. What I do is I run a shell script like so, then I execute my paramiko python script, then I kill the
ssh -N remote_server#54.221.226.240 -i ~/.ssh/my_ssh_key.pem -L 5433:localhost:5432
python paramiko_connect.py
kill pkill -f my_ssh_key.pem # kill using the pattern,
#see ''ps aux | grep my_ssh_key.pem'' to see what it will kill
-N means don't execute any commands, -L is the local port to tunnel from, followed by the remotes server port, assuming you are connected to that server already.
Works like a charm for me for my postgres server & I did try it on mysql too.

Reverse tunnel works manually, not for replication

My MASTER mysql server is on a local network, and I have a new slave which is remote (i.e. on the internet). As MASTER does not have an accessible IP, I gathered from the docs that I should establish a reverse tunnel. I execute this:
ssh -f -N -T -R 7777:localhost:3306 user#slave.slave.com
on the MASTER. The connection seems to work - I can go to the slave and connect
with mysql to the MASTER without problem. For some reason though, replication does
not start. MASTER is already replicating to two other slaves without problems - seems the configuration is correct there.
I initiated replication on the slave as:
CHANGE MASTER TO MASTER_HOST='127.0.0.1',
MASTER_PORT=7777,
MASTER_USER='my_repl',
MASTER_PASSWORD='xxxxx',
MASTER_LOG_FILE='mysql-bin.nnnnn',
MASTER_LOG_POS=mm;
SLAVE STATUS reports mysql trying to connect to the remote, but never succeeding:
error connecting to master 'my_repl#127.0.0.1:7777' - retry-time: 60 retries: 86400
Can anyone suggest how to diagnose this problem?
BTW: OS is Linux.
My apologies... I didn't realize I had to define a new user with 127.0.0.1 as
IP.
So, 'intranet' connections use
replication_user#machine_name
as id, the connection which comes through the reverse tunnel uses
replication_user#127.0.0.1
as id. Both have to be declared to mysql separately. The rest of the info in the original message is valid - maybe this helps someone...
Greetings,
John
PS: Forgot to mention - I debugged this remotely (both MASTER and SLAVE are remote to me) using tcpdump:
tcpdump -i lo 'tcp port 7777'
on the SLAVE side, and
tcpdump -i lo 'tcp port 3306'
on the MASTER (of course that would not be very useful when there is much traffic).

execute mysql on remote server via bash script

I need to execute a mysql command on a remote server but seem to be hitting problem when it comes to executing the actual mysql bit
#!/usr/bin/expect -f
spawn /usr/bin/ssh -t root#10.0.0.2
expect "password: "
sleep 1
send "password\r"
sleep 2
/usr/bin/mysql databasename -e "update device_log set status = 'Y' where device_id in ('1','2');"
basically I want to change the flag to Y on device id's 1&2
but the script outputs
invalid command name "/usr/bin/mysql"
Just append the mysql command to the ssh command to run it in one go, like this:
#!/usr/bin/expect -f
spawn /usr/bin/ssh -t root#10.0.0.2 /usr/bin/mysql databasename -e "the query"
expect "password: "
sleep 1
send "password\r"
I'm not very much into expect, but I'm expecting that your attempt in the mysql line isn't actually valid syntax for expect to run a command.
Additionally:
You should use SSH keys for passwordless login instead of having a root password hardcoded in a script.
Consider running MySQL remotely e.g. mysql -h 10.0.0.2 -e "the query", or
Use port forwarding in SSH to connect to MySQL securely, e.g. run ssh -L 3307:localhost:3306 root#10.0.0.2 in the background and then connect to TCP port 3307 on localhost mysql -h 127.0.0.1 -P 3307.
It sounds like /usr/bin/mysql is not the the path to the mysql binary on that remote server. You could use just mysql instead, assuming that the binary is somewhere in that remote server's PATH. Otherwise you will have to go and find out where the binary is actually located and alter the absolute path accordingly.

What's the best way to allow MySQL on one server to listen to requests from two other different servers?

I have my MySQL database server on Server 1. I want to have my Rails apps on two other servers - say A and B to be able to connect to this Server 1. What's the best way to do this?
In the my.cnf file it appears I can use the bind-address to bind to one and only one IP address. I can't specify the IP addresses of both A and B in my.cnf.
On the other hand, if I comment skip-networking, the gates are wide open.
Is there a golden mean? What are you folks doing to allow a DB server to listen to requests from multiple app servers and still stay secure?
If MySQL is running on Linux:
I am very biased towards using iptables (a.k.a. netfilter, the Linux firewall) to control incoming traffic to various ports. It's simple to use and very robust.
iptables -A INPUT -p tcp -s server1address/32 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s server2address/32 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP
The bind address is the local IP address of the server, not the allowable client addresses. In your situation, you can provide the static address of your server (in place of localhost) or, if your IP might change, just comment it out.
Again, to clarify: the bind-address is the address on which the server listens for client connections (you could have multiple NICs, or multiple IP addresses, etc.). It is also possible to change the port you want mysql to listen to.
You will want to make sure you configure the root password if you haven't already:
mysql> SET PASSWORD FOR 'root'#'localhost' = PASSWORD('yourpassword');
You would then use other means to restrict access to MySql to something like the local network (i.e. your firewall).
More info about iptables:
The iptables commands above must either be inserted in the existing iptables tables, or else you must delete the existing stuff and start from scratch with the commands above.
Insertion is not hard, but it depends a little bit on the Linux distribution you use, so I'm not sure what to recommend.
To start from scratch, you need to Flush and eXpunge the existing tables first:
iptables -F
iptables -X
Then insert the iptables firewall rules that you need to use, following the model indicated in my previous answer.
Then save the iptables rules. This is again distribution-dependent. On most Red Hat derivatives (Red Hat, Fedora, CentOS), it's enough to run:
service iptables save
Voila, your custom rules are saved. If the iptables service is enabled (check with "chkconfig --list iptables", it must be ":on" on runlevels 3 and 5, depending on your situation, but it's safe to set it ":on" on both 3 and 5 in any case) then your rules will survive the reboot.
At any time, you can check the current running iptables rules. Here's a few commands that do that, with various levels of verbosity:
iptables -L
iptables -L -n
iptables -L -n -v
Without -n, it will try to lookup the domain names and display them instead of IP addresses - this may not be desirable if DNS is not working 100% perfect.
So that's why I almost always use -n.
-v means "verbose", a bit harder to read but it gives more information.
NOTE: If you start from scratch, other services running on that machine may not be protected by iptables anymore. Spend some time and figure out how to insert the MySQL rules in the existing tables. It's better for your system's security.
In addition to getting the bind address right you'll need to open the correct port, create or configure the users and some other details. This explains it pretty clearly.
A DB server will listen to an indefinite number of clients.
Each client Rails app identifies the DB server.
The DB server waits patiently for connections. It has no idea how many clients there are or where the connections come from.
Edit
"how do you securely configure the DB wrt what servers to accept requests from?"
That's what networks, firewalls and routers are for.
That's why the database requires credentials from the Rail apps.