MySQL Master-Master Replication over a Secure Stunnel Connection (SSL)
Posted by Admin • Saturday, February 7. 2009 • Category: Code and HacksFirst of all - I won't go into the steps for setting up Master-Master itself - that's very well documented. Let's assume that you can convince one of your mysql's to slave off the other, and vice versa. (I used this page as a guide).
With that accomplished, let's assume that the boxes are not sitting next to each other but are in separate colo's or offices, and have some insecure internet to go between them (or maybe you don't even trust the local LAN). Yes, MySQL does have built-in SSL stuff, but so far the consensus is that it's rather difficult to work with. Moreover, I am more willing to trust stunnel (just my feeling on it).
Why not use ssh? Using something like ssh -n with a for loop that restarts it just doesn't sound enterprise-grade. I want something that actively reconnects when needed, based on active usage, and is actually intended for this. I still use SSH for port tunnelling all the time, but those are short-lived tunnels for my own personal use or debugging.
So our goals are: Secure transport and identity validation. Here we go.
Step By Step
I am doing this on ubuntu-server. Other distros should be similar.Note also that I'm not explaining the security implications of these steps in great detail - you are expected to read up on this if you don't know already.
- MySQL better be installed on both boxes and up and running. Note: this approach does not care if MySQL is bound to localhost or the public network interface, as it uses 3 ports to keep everything distinct
- install stunnel (eg apt-get install stunnel)
- generate some certs (This is well documented in openssl documentation, but I did it this way):
- openssl req -new -x509 -days 3650 -nodes -config /etc/ssl/openssl.cnf -out stunnel.pem -keyout stunnel.pem
Notice that I cranked up my days to 10 years for simplicity. This command generates both private and public keys at once, placing both in the same file. - Place stunnel.pem in /etc/stunnel/
- Place same stunnel.pem in /etc/stunnel/client.pem on the other box
- chmod 600 /etc/stunnel/*.pem
- Repeat 1-4 on the other box
- You should now have reciprocal cert files sitting around and doing nothing (yet)
- openssl req -new -x509 -days 3650 -nodes -config /etc/ssl/openssl.cnf -out stunnel.pem -keyout stunnel.pem
- If on Ubuntu, edit /etc/default/stunnel4 to enable stunnel altogether - set ENABLED to 1. Once you do this, the init.d script will start a new stunnel for each *.conf file it finds in /etc/stunnel/
- On both boxes, copy original stunnel.conf to client.conf (filename is up to you). Edit these lines:
cert=/etc/stunnel/client.pem pid = /client.pid output = /var/log/stunnel4/client.log ; optional, enable debug = 7 also client = yes [mysqlreplication] accept = 3307 connect = box2:3308 ; Change to box1 on box2 retry = yes
- Edit stunnel.conf in /etc/stunnel - that will be your server conf file. Do this on both boxes. Relevant items:
cert = /etc/stunnel/stunnel.pem key = /etc/stunnel/stunnel.pem verify = 2 CAfile = /etc/stunnel/stunnel.pem [mysqlreplication] accept = 3308 connect = 3306
- start up stunnel and you should see the following (on both boxes):
- telnet localhost 3306 - should show you mysql garbage
- telnet localhost 3308 - should stay quiet and hang up on you (ssl handshake)
- telnet localhost 3307 - should show you mysql garbage only if the other box is fully working - take down mysql there to verify you are talking to the right place
Troubleshooting
Stunnel is kind of weird to troubleshoot, but here are some pointers.You can run "stunnel /etc/stunnel/WHATEVER.conf -d7 -f" and it should (most of the time) output what it doesn't like about your configuration. That said, there was one case where it would not say anything, or log anything, and that was because that instance was already running! (ps aux | grep stunnel).
Do not be mislead by this error message:
You should check that you have specified the pid= in you configuration file. Assuming that you did make the pid files distinct (as I did above), the error message merely means that stunnel returned 1 and not 0, for absolutely any reason.
Check what you have running using ps aux | grep stunnel. There should be several processes for each conf file, and when you stop stunnel, there should be none.
Stunnel is pretty resilient and reliable, but in my experience it doesn't like dynamic IPs. Because some of my facilities are not static, I have a cronjob that restarts stunnel nightly - in case the IP changed that day. I can tolerate a slight replication delay, but if you cannot then you may want to trigger a stunnel restart on IP change.
Thx a lot mate!
I was searching for this solution for a couple of days... U saved my life, literally.. Great article!
Have a nice day and thx a lot!!