Category Archives: technical

automating mysql backups

I want to backup all of the MySQL databases on my server on a routine basis.

As I started asking how to get a list of all databases in MySQL on Stack Overflow, I came across this previous SO question, entitled, “Drop All Databases in MySQL” (the best answer for which, in turn, republished the kernel from this blog post). Thinking that sounded promising, I opened it and found this little gem:

mysql -uroot -ppassword -e "show databases" | grep -v Database | grep -v mysql| grep -v information_schema| |gawk '{print "drop database " $1 ";select sleep(0.1);"}' | mysql -uroot -ppassword

That will drop all databases. No doubt about it. But that’s not what I want to so, so I edited the leading command down to this:

`mysql -uroot -e "show databases" | grep -v Database | grep -v mysql| grep -v information_schema| grep -v test | grep -v OLD | grep -v performance_schema

Which gives back a list of all the databases created by a user.

Now I need a place to keep the dumps .. /tmp sounded good.

And each database should be in its own file, for I need mysqldump $db.identifier.extension

Made the ‘identifier’ the output of date +%s to get seconds since the Unix epoch (which is plenty unique enough for me).

All of which adds up to this one-liner:

for db in `mysql -uroot -e "show databases" | grep -v Database | grep -v mysql| grep -v information_schema| grep -v test | grep -v OLD | grep -v performance_schema`; do mysqldump $db > /tmp/$db.dump.`date +%s`.sql; done

Plop that puppy in root’s crontab on a good schedule for you, and you have a hand-free method to backup databases.

Thought about using xargs, but I couldn’t come up with a quick/easy way to uniquely identify each file in the corresponding output.

Might consider adding some compression and/or a better place for dumps to live and/or cleaning-up ‘old’ ones (however you want to determine that), but it’s a healthy start.

You can also do mysqldump --all-databases if you think you want to restore all of them simultaneously … I like the idea of individually dumping them for individual restoration / migration / etc.

The full script I am using (which does include backups, etc):



echo 'Archiving old database backups'

tar zcf mysql-dbs.`date +%s`.tar.gz ~/sqlbackups
rm -f ~/sqlbackups/*


echo 'Backing up MySQL / MariaDB databases'

for db in `mysql -uroot -e "show databases" | grep -v Database | grep -v mysql| grep -v information_schema| grep -v test | grep -v OLD | grep -v performance_schema`; do mysqldump $db > ~/sqlbackups/$db.dump.`date +%s`.sql; done

echo 'Done with backups. Files can be found in ~/sqlbackups'


change your default font in windows 10

Starting from a tutorial I found recently, I want to share how to change your default font in Windows 10 – but in a shorter edition than that long one (and in, I think, a less-confusing way).

Back in the Good Ole Days™, you could easily change system font preferences by right-clicking on your desktop, and going into the themes and personalization tab to set whatever you wanted however you wanted (this is also where you could turn off (or back on) icons on your desktop (like My Documents), set window border widths, colors for everything, etc).

Windows 10 doesn’t let you do that through any form of Control Panel anymore, so you need to break-out the Registry Editor*.

0th, Start regedit

WindowsKey-R brings up the Run dialog – type regedit to start the Registry Editor

2016-07-27 (3)

NOTE: you should back-up any keys you plan to edit, just in case you forget what you did, want to revert, or make a mistake.

1st, Navigate to the right key area
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts

2016-07-27 (1)Are where you’ll need to be to make these changes.

2nd, Blank entries for Segoe UI

For all of the “Segoe UI” entries in Fonts, change their Data field to blank (“”)

3rd, Add a Segoe UI substitute font

In FontSubstitutes, click Edit->String Value. Name it “Segoe UI” (without the quotes). In the “Value data” field, enter your preferred font name. I used Lucida Console.

2016-07-27 (2)

4th, Logout, or reboot, and login again to see your changes take effect.

* You can also download my registry keys, which have the substitution already done here. And you can pick any other font instead of Lucida Console you like – just edit the key file in your favorite text editor (I like TextPad) before merging into your Registry.

there is no such object on the server

Gee. Thanks, Active Directory.

This is one of the more useless error messages you can get when trying to programmatically access AD.

Feel free to Google (or DuckDuckGo, or Bing, or whomever) that error message. Go ahead, I’ll wait.

Your eyes bleeding, and gray matter leaking from your ears yet? No? Then you obviously didn’t do what I just told you to – go search the error message, I’ll be here when you get back.

Background for how I found this particular gem: I have a customer (same one I was working with on SAP a while back where I had BAPI problems) that is trying to automate Active Directory user provisioning with HP Operations Orchestration. As a part of this, of course, I need to verify I can connect to their AD environment, OUs are reachable, etc etc.

In this scenario, I’m provisioning users into a custom OU (ie not merely Users).

Provisioning into Users doesn’t give this error – only in the custom OU. Which is weird. So we tried making sure there was already a user in the OU, in case the error was being kicked-back by having and empty OU (if an OU is empty, does it truly exist?).

That didn’t help.

Finally, after several hours of beard-stroking, diving into deep AD docs, MSDN articles, HP forae, and more … customer’s AD admin says, “hey – how long is the password you’re trying to use; and does it meet 3-of-4?” I reply, “it’s ‘Password!’ – 3-of-4, 9 characters long”. “Make it 14 characters long – for kicks.”

Lo and behold! There is a security policy on that OU that mandates a minimum password length as well as complexity – but that’s not even close to what AD was sending back as an error message. “There is no such object on the server”, as the end result of a failed user create, is 100% useless – all it tells you is the user isn’t there. It doesn’t say anything about why it isn’t there.


Yet another example of [nearly] completely ineffective error messages.

AD should give you something that resembles a why for the what – not merely the ‘what’.

Something like, “object could not be created; security policy violation” – while not 100% of the answer – would put you a lot closer to solving an issue than just “there is no such object on the server”.

Get it together, developers! When other people cannot understand your error messages, regardless of how “smart” they are, what field they work in, etc, you are Doing It Wrong™.

new service – free, secure password generation

Today, I am formally announcing a brand-new service / website for secure password generation.

Go visit

Get yourself random passwords of commonly-required lengths and complexities*.

Password Varieties:

  • 4 of 4
  • upper & lower alphanumeric
  • lower alphanumeric

Lengths generated: 12, 16, & 24 characters

Visit the GitHub project page ..

.. if you want to run the site on your own server.

You can view the source “live” ..

.. if you’d like to see how it works without visiting GitHub – and verify nothing is saved anywhere by the code: it’s just a script with no filesystem / database access.

It’s fast ..

.. load times tend to be under 0.15 seconds!

It will always be linked from my Projects page, and from the ‘External’ links menu on this blog.

*Also findable at – same server, same code

turn on spf filtering with postfix and centos 7

After running my new server for a while, I was noticing an unusually-high level of bogus email arriving in my inbox – mail that was being spoofed to look like it was coming from myself (to myself).

After a great deal of research, I learned there is a component of the DNS specification that allows for TEXT or SPF records. Sender Policy Framework was developed to help mail servers identify whether or not messages are being sent by authorized servers for their representative domains.

While there is a huge amount of stuff that could be added into a SPF record, what I am using for my domains is:

"v=spf1 mx -all"

Note: some DNS providers (like Digital Ocean) will make you use a TEXT record instead of a dedicated SPF record (which my registrar / DNS provider Pairnic supports).

If they require it be via TEXT record, it’ll look something like this: TXT @ "v=spf1 a ~all"

Starting with this old how-to I found for CentOS 6, I added the policy daemon for Postfix (though it’s now in Python and not Perl) thusly:

yum install pypolicyd-spf

(I already had the EPEL yum repository installed – to get it setup, follow their directions, found here.)

Then I edited the config file for Postfix, adding the following at the bottom:

policy unix - n n - 0 spawn user=nobody argv=/bin/python /usr/libexec/postfix/policyd-spf

Note: those are actually tabs in my config file – but spaces work, too.

When you’re done with your edits and record additions, restart Postfix:

systemctl restart postfix

Then you’ll see messages like this in your /var/log/maillog file:

Apr 23 18:58:59 khopesh postfix/smtpd[18199]: NOQUEUE: reject: RCPT from unknown[]: 550 5.7.1 <>: Recipient address rejected: Message rejected due to: SPF fail - not authorized. Please see;;ip=;; from=<> to=<> proto=ESMTP helo=<[]>

And if you follow the directive to go visit the “Why” page on OpenSPF, you’ll see something like this explanation:

Why did SPF cause my mail to be rejected?

What is SPF?

SPF is an extension to Internet e-mail. It prevents unauthorized people from forging your e-mail address (see the introduction). But for it to work, your own or your e-mail service provider’s setup may need to be adjusted. Otherwise, the system may mistake you for an unauthorized sender.

Note that there is no central institution that enforces SPF. If a message of yours gets blocked due to SPF, this is because (1) your domain has declared an SPF policy that forbids you to send through the mail server through which you sent the message, and (2) the recipient’s mail server detected this and blocked the message. rejected a message that claimed an envelope sender address of received a message from that claimed an envelope sender address of

However, the domain has declared using SPF that it does not send mail through That is why the message was rejected.

helping a magpierss-powered site perform better

I rely on MagpieRSS to run one of my websites. (If you'd like to see the basic code for the site, see my GitHub profile.)

One of the drawbacks to Magpie, and dynamic websites in general, is they can be bottlenecked by external sources – in the case of Magpie, those sources are the myriad RSS feeds that Datente draws from.

To overcome some of this sluggishness, and to take better advantage of the caching feature of Magpie, I recently started a simple cron job to load every page on the site every X minutes – this refreshes the cache, and helps ensure reader experience is more performant. By scheduling a background refresh of every page, I cut average page load times by nearly a factor of 10! While this is quite dramatic, my worst-performing page was still taking upwards of 10 seconds to load a not-insignificant percentage of the time (sometimes more than a minute!) 🙁

Enter last week's epiphany – since RSS content doesn't change all that often (even crazy-frequent-updating feeds rarely exceed 4 updates per hour), I could take advantage of a "trick", and change the displayed pages to be nearly static (I still have an Amazon sidebar that's dynamically-loaded) – with this stupidly-simple hack, I cut the slowest page load time from ~10-12 seconds to <1: or another 10x improvement!

"What is the 'trick'," you ask? Simple – I copied every page and prefixed it with a short character sequence, and then modified my cron job to still run every X minutes, but now call the "build" pages, redirecting the response (which is a web page, of course) into the "display" pages. In other words, make the display pages static by building them in the background every so often.

If you'd like to see exactly how I'm doing this for one page (the rest are similar), check out this stupidly-short shell script:

(time (/bin/curl -f > ~/temp.out)) 2>&1 | grep real

(The time is in there for my cron reports.)

Compare the run time to the [nearly] static version:

(time (/bin/curl -f > ~/temp.out)) 2>&1 | grep real