I have two accounts on GitHub: Personal and work. How do I access both from the same computer without getting them confused? I have two different ssh keys and use .ssh/config to do the right thing. Some bash aliases also help.


Why is it important to me that I keep these two accounts separate?

First, certain repos can only be accessed from one account or the other. Public repos can be accessed from either, but private repos are not so lucky.

Second, I want the commit logs for different projects should reflect whether I am "Tom the person" or "Tom the employee". My work-related repos shouldn't be littered with my personal email address. It is ugly and, more importantly, it would mean that someone searching for my commits would have to do two searches: one for each of my names. My username is different at my work account ("tlimoncelli" vs. "tal)... how could I expect a coworker to know that?.)

Lastly, when I contribute to a third-party project it is a very intentional decision whether I am contributing as a StackOverflow employee or as myself. I want bug reports and other notifications sent to one email address or the other depending on the situation. Also, this future-proofs things so that when I change jobs (no current plans, BTW), I'll stop receiving notifications from projects that I'm involved in for work-related reasons.

What doesn't work?

You can't upload the same SSH public key to GitHub two accounts. GitHub uses the key to determine which account you are accessing, so they must be unique. If you were able to upload the same key to both accounts, GitHub would have to guess your intention for each repo, and that guess would often be wrong. You can upload multiple keys to each account, but there may not be overlapping keys between the accounts.

I could simply decide that one machine will be only for work, and will have SSH keys associated with my work account. I would then have a different machine that I'd only use for personal stuff, and will have an SSH key there that is only associated with my personal account. However, expecting me to carry around 2 laptops is silly. That isn't to say that some companies should adopt such a policy, especially ones that have higher security requirements, but that's not my situation.

What do I do?

I set up a fake hostname in .ssh/config to indicate which SSH key to use.

Here's an example:

git clone [email protected]:StackExchange/httpunit.git
git clone [email protected]:StackExchange/httpunit.git
              ^^^^^^^^^^^^^^^ What??? That's not a thing!

There is no such thing as home-github.com or work-github.com. However, if you look at my .ssh/config file you'll find a "Host" entry that sets the actual hostname and sets a bunch of parameters, including which SSH key to use:

# Personal GitHub account:
Host home-github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519-homegithub
  PreferredAuthentications publickey
  PasswordAuthentication no
  IdentitiesOnly yes

# Work GitHub account:
Host work-github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519-workgithub
  PreferredAuthentications publickey
  PasswordAuthentication no
  IdentitiesOnly yes

On any machine that I use git, I simply make sure that the filename points to the appropriate key.

When someone gives me an SSH-based Git URL, I manually doctor the hostname by adding the "home-" or "work-" prefix. After that, everything just works.

If I forget to edit the hostname, I have defaults set so that it uses my work key. Originally I set it up so that using the undoctored hostname fails. That way I'd get an error and remember to doctor the hostname. However I found that interfered with systems (usually install scripts) that didn't let me edit the hostname.

Things like go get are unaffected by this system since they use anonymous HTTP, not Git.

Setting the user.email correctly

The other problem I had was properly configuration git user.name and user.email. My global ~/.gitconfig file sets user.name because I am always Tom Limoncelli. However, I leave user.email unset in that file to force me to set it per-repo.

I've set up Bash aliases to let me easily set the email address:

alias gitmeHome='git config user.email [email protected]`
alias gitmeWork='git config user.email [email protected]`

After I do "get clone", I need to remember to cd into that repo and run either gitmeHome or gitmeWork. If I forget, I get this nice reminder:

$ git commit filename
[master 5667341] yes
 Committer: Tom Limoncelli <[email protected]>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email [email protected]

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 dirname/filename

By having the bash aliases, setting user.email is without hassle.

One more thing.

I've found it greatly simplifies my life to have the exact same ~/.ssh/config and ~/.gitconfig file on all my machines.

Manually adding a new Host entry to ~/.ssh/config on the proper machines is a pain. It is easier to copy the entire master file (which I keep in git, of course) is easier. If a particular machine doesn't need that Host entry, who cares? Either I won't use it, or it will fail if I do use it. My Host entries are carefully constructed so that they work if the right keys are on the machine, and fail otherwise.

Having the same ~/.gitconfig on all my machines is a little more tricky. It contains the settings that are the same everywhere. Overrides are set in the repo-specific .git/config file. As you saw above, a setting like user.email is critical, so I have no default in the global file thus the per-repo setting is required.

Posted by Tom Limoncelli in Technical Tips

RIP John Boris

John was active in the LOPSA community. I saw him at nearly every LOPSA-NJ meeting, where he was active in planning and hosting the meetings. He was also on the board of LOPSA (national) where he will be greatly missed.

John was also a football coach at the school where he worked in the IT department. It was very clear that his coaching skills were something he applied everywhere, including his helpfulness and mentoring at LOPSA.

I had a feeling that when I hugged him at the end of the January LOPSA meeting it might be the last time I saw him. He was recovering from bypass surgery and was looking worn. He was chipper and friendly as always. He was a good guy. Easy to get along with. He kept LOPSA-NJ and many other projects going.

John Boris passed away last night.

I'll miss him.


Info about his service:

  • Friday Jan 20th
  • Visitation: 1030am to noon
  • Memorial Mass: noon
  • St Joseph the Worker Parish,
  • St Aloysius Church, 37 W Hadden Ave, Oaklyn, NJ 08107

In lieu of flowers donations can be made to Camden Catholic high school football program, Cherry Hill, NJ c/o Nick Strom.

Posted by Tom Limoncelli in LOPSA

My coworker did a bang-up job on this blog post. It explains a lot about how DNS works, how the Dyn DDOS attack worked (we missed it because we don't use Dyn), and the changes we made so that we'll avoid similar attacks when they come.

How Stack Overflow plans to survive the next DNS attack

Posted by Tom Limoncelli in Stack Exchange, Inc.

Hey NYC-area folks!

The NYC DevOps meetup is springing back to life! Our next meeting will be Tuesday, January 17, 2017 from 6pm-7:30pm. The meeting is at the Stack Overflow NYC headquarters near the financial district. For complete details, visit https://www.meetup.com/nycdevops/events/236646177/

From the announcement:

Please join us on January 17th from 6:00 - 7:30 PM at Stack Exchange for our first annual DevOps Mixer. Our goal is to re-engage with our members for an inaugural meet and greet with our new team of organizers, awesome community members, and of course there will be refreshments! Come socialize with us and talk about your experiences, what's new, what you're working on and what you would like to see from the NYC DevOps Meetup.

We're also looking for members of the local community to participate in future meetups by giving some great talks about things that you're working on, and participate on interactive panels. Come with ideas on topics you'd like to hear about!

Finally, please provide your feedback on how we can best serve the NYC DevOps Community members via this survey: https://www.surveymonkey.com/r/Z2C2FT5

Hope to see you there!



Posted by Tom Limoncelli in NYCDevOps

I write a thrice-yearly column in acmqueue Magazine. The Dec 20 issue has my newest entry, "Are You Load Balancing Wrong?"

You can read it at this URL:


acmqueue is free for ACM professional members. Non-members can purchase an annual subscription for $19.99 or a single issue for $6.99. Download the app from iTunes or Google Play, or view within your browser. More information here.

Posted by Tom Limoncelli in ACM Queue Column

I'll be the speaker at LOPSA-NJ/Montclair in February. Hope to see you there!

The February meeting will be held at Montclair State University.

  • Topic: Stealing the Best Ideas from DevOps: A Guide for Sysadmins without Developers
  • Speaker: Tom Limoncelli, StackOverflow.com
  • Date: WEDNESDAY, February 1st, 2017, 7pm (not Thursday)
  • Location: Montclair University, CELS 110, 1 Normal Ave, Montclair, NJ 07043

Talk Description: This talk will present the DevOps principles in terms that apply to all system administrators, and use case studies to explore their use in non-developer environments. DevOps is not a set of tools, nor is it just automating deployments. It is a set of principles that benefit anyone trying to improve a complex process.

For more information, and to rsvp, please visit the Meetup page:


NOTE: The January meeting will be on Thursday, Jan 5, 2017 at 7pm at the south jersey location (Lawrence Headquarters Branch of the Mercer County Library). More info here.

Posted by Tom Limoncelli in LOPSASpeaking

Someone recently asked me how the flags in "flag flips" are implemented in actual software. There are a couple different techniques that I've seen.

  • Command-line flags: Normal command line flags. To change a flag, you have to kill and restart the process. These flags are usually implemented in libraries that come with the language, though I have a preference for gflags.

  • A/B flags: When doing A/B testing, a cookie is set with a random number (often a value 0-999). The code then uses the number to partition the tests: A=0-499, B=500-999. To enroll 1 percent of all users, one might use A=0-4 and B=5-9 and everyone else gets the default behavior. Often these ranges are set in command-line flags so they are easy to change.

  • Dynamic flags are more difficult: Some sites use a PAXOS-based system so that all processes get the same flag change at the same time. You have one thread call a blocking "return when the value changed" call so you can stash the new value and start using it right away. Google uses Chubby internally, the GIFEE equivalent is called ZooKeeper, and CoreOS has open sourced etcd.

  • More complex systems Facebook has an interesting system, which we talk about in The Practice of Cloud System Administration; Chapter 11 that permits per-user settings such as don't show a certain feature to people that work for TechCrunch.

The person that wrote to me also asked how would I change many machines at the same time. For example, on January 1st all your web pages must switch from Imperial to Metric for all dimensions displayed to the user. How would this be managed?

Well, first you'd have to decide how to deal with computations that are already in flight? I would redefine the problem to be: "all new API calls after midnight will have the new default". The API dispatcher should check the clock and read all flags, which are then passed to the function. That way the flags are invariant. It also makes it easier to write unit tests since the flag setting mechanism is abstracted out of the main code. Also, I say "default" because before midnight you'll want to be able to call the API both ways for testing purposes. By having the dispatcher calculate the default based on the date/time, and letting that trickle down to the derived value, you permit the caller to get the old behavior if needed.

If readers want to recommend libraries that implement these in various languages, please feel to post links in the comments.

Posted by Tom Limoncelli in Technical Tips

Ben Linders interviewed Tom, Christine and Strata about the 3rd edition of The Practice of System and Network Administration:

  • See what's new in the 3rd edition of The Practice of System and Network Administration.
  • Learn how to steal DevOps practices for use in enterprise IT and desktop support.
  • What's better than beta testing IT services? Many small batch launches.
  • Learn how bi-directional empathy creates a collaborative IT culture.
  • What can go wrong when launching a new service? Everything! Here's how to avoid surprises.

Plus: InfoQ readers can download a book extract with a discount code.

Read the interview here.

Posted by Tom Limoncelli in TPOSANA 3rd Edition

Gall bladder Removal

Today I say goodbye to my gall bladder. I'll miss you, little guy.

I scheduled this blog post to appear around the time I should be coming out of surgery. Recovery should be pretty fast (a few days).

Here's the story told in cartoon form:

You can read all of The Awkward Yeti's cartoons involving gall bladder here.

See you soon!

Posted by Tom Limoncelli in Misc

Congrats to the LISA organizing committee for another successful conference! The Usenix LISA conference was in Boston this year, and ran Sunday to Friday as usual. This was the 30th conference.

What I learned:

  • I learned that the coming generation of servers from Dell/HP/etc. will have terabytes of persistent RAM (RAM that retains info between reboots). Operations will have to radically change how they do operations (rebooting won't clear RAM). Software engineers will be re-thinking software designs. (John Roese, Dell EMC)
  • I learned that Homomorphic encryption lets you do math on encrypted data, and you get encrypted results. No need to decrypt the source material. I also learned the limits of blockchain/bitcoin hype. (Radia Perlman)
  • I learned that story telling is more powerful than facts, and it can be as simple as starting out a presentation with an anecdote that involves a conflict and a resolution. (Jessica Hilt)
  • I learned that Total Ownership Model solves a lot of operations ills by making everyone responsible for uptime, so devs and ops have an inventive to work together. (Courtney Eckhardt)
  • I learned that Facebook's slides had all IPv6 examples, and icons for "clients" were always phones. Welcome to the future! (Patrick Shuff)
  • I learned that a non-obvious benefit of using declarative languages for configuration management is that the "preview what changes will be made" feature is practically automatic. (Mitchell Hashimoto, HashiCorp)
  • I learned that ants invented TCP/IP's rate-limiting algorithm. (Jane Adams, Two Sigma)
  • I learned that Christine Hogan and I can co-present, finish on time, and people will laugh at our jokes. (Limoncelli/Hogan)
  • I learned that the LGBTQAA* BoF session had many attendees that were concerned that the title should use .* (a regex) instead of * (a glob). (link)
  • I learned that a slack.com channel for a conference is great, even when it is unofficial.
  • I learned that Google is in awe that StackOverflow still doesn't need to shard its database. (Niall Murphy and Todd Underwood, Google)
  • I learned that a story I told during one tutorial would make a good short-form poem at another. (link)
  • I learned that Jupyter is an amazing lab notebook. It is a shame I don't use Python any more.
  • I learned that Machine Learning can be done on a laptop with Python, and useful results can be done without having terabytes of data and thousands of machines. (Matt Harrison, MetaSnake)
  • The SESA '16 conference (co-located with LISA): I learned about some massive (16,000 students/year) sysadmin education programs, how DevOps can be integrated into university-level system administration curriculum, and more.

The conference gaVe me foresight into technology that will be coming to products in the next 6-18 months and how my job will be affected. It also gave me a lot of new ideas I can implement right away.

I'd also like to thank the people that attended my 2 tutorials, the book signing, and the 3 presentations that Christine and I did. We distributed more than 300 flyers and coupons for our books, and gave away 20 free copies of TPOSANA/TPOCSA. I met a lot of new people this year; definitely more than last year.

I'm looking forward to LISA '17, which will be in San Francisco, October 29-November 3, 2017. The call for participation will be announced soon. Next year's chairs are Connie-Lynne Villani and Caskey Dickson. I look forward to their amazing conference!

Posted by Tom Limoncelli in LISA

  • LISA16