Cover Image

Setting Up a CentOS Server

2023 words. Time to Read: About 20 minutes.

I’m slowly discovering that I love systems stuff. I’ve always used Ubuntu as the flavor of Linux on my servers, but I was curious about the differences between Ubuntu and CentOS, so I looked up a few guides and tutorials and spun up a new Digital Ocean droplet with a fresh install of CentOS. I wanted to share what I learned, and all of the things to think about when first getting things set up. I’m also writing this for when future me forgets a step and can’t remember the commands.

I’m going to assume that you have working knowledge of the command line for now: changing directories, editing files, and setting file permissions. I’ll try to explain anything more exotic than that. If you’re not quite there, but you still want to learn, please get in touch, and I’d be happy to walk you through it (and/or write another post for that). This is also a guide for CentOS because that’s what I was doing. For that reason, all of the commands are Centos (and probably RHEL) specific. The process and theory should be much the same for other flavors of Linux, though.

First Contact

I’m not sure how other providers do it, but once you create a droplet on Digital Ocean and your new server is all turned on, they send you an email with the root password. You’ll be able to ssh into your server using these credentials. If you’re on a Mac, you already have ssh installed and accessible via your terminal app of choice. If you’re on Windows, you should look into an ssh client. I use PuTTY when I need to. Your hosting provider will provide you with an IP address as well.

ssh root@<your_server_ip>

From now on, if you see something in angle brackets like that, just assume that I mean, “Fill in the placeholder in angle brackets with your own preferred value.” It will ask you for your password. Paste it in and hit Enter, and you should be ready to rock!

Check Your Privilege

Right now you’re logged in as root. This is great! It is also bad. When you are logged in as root, typos and little mistakes can cause big problems. It’s generally better to sign in and go about your life in a less privileged account, only invoking sudo to do privilege-y things when you need to. That way, if you accidently try to delete yourself out of existence, you’ll have to work a little harder before you succeed. So, we’ll need to create this everyday user.

adduser <username> && passwd <username>

This will ask you for a new password for your new user. Make it a good one.

Next, let’s make sure that your new user can actually sudo.

usermod -aG wheel <username>

We’re adding our new user to the wheel group, which (as long as you’re on CentOS 7 or better) means that we’ll be able to sudo without trouble.

Lastly, sometimes there’s a default user created: centos. I don’t think we need this user for anything. Remove it with:

deluser centos

Transferring Keys

Next, we’re going to strengthen security by setting up private/public key authentication. A side benefit of this is that you won’t need to remember a password if you don’t want to anymore. Temporarily switch users so that you’re operating as your new user.

su <username>

In order to authenticate with keys, you’ll need a spot to put your public key. Let’s create the .ssh directory.

mkdir ~/.ssh

We also don’t want anyone but us to be able to fiddle around in this directory.

sudo chmod 700 ~/.ssh/

Great! Let’s transfer a key. Exit ssh or open up a new terminal on your local machine. If you don’t yet have a private/public key pair, generate one now.

ssh-keygen

# Generating public/private rsa key pair.
# Enter file in which to save the key (/Users/localuser/.ssh/id_rsa):

Just hit Enter to accept the default file location for your keys. This will create two files. id_rsa is your private key. This is Very Secret™. Never share this with anyone unless you trust them with your life. Or, at least, your servers. I’d go so far as to say don’t put this out on a cloud service or flash drive where it might get hacked, stolen, lost, or blown up. id_rsa.pub is your public key, and this is the one you can share with people to prove you are who you say you are. This is the file that we want to share with our new server’s new user. There are a couple ways to do this:

# Via ssh-copy-id
ssh-copy-id <username>@<server-ip>

# Via scp
scp ~/.ssh/id_rsa.pub <username>@<server-ip>:~/.ssh/authorized_keys

# Manually via good ole' fashioned copy/paste
cat ~/.ssh/id_rsa.pub

# You'll see something like:
# ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAmLmwkzQDjEOW1Rj3TP5NldVDqUODVH9xuYrkeaSkxtdP

# Copy the whole thing.  Then ssh back into your server like normal and create a new file at ~/.ssh/authorized_keys and paste in in.
nano ~/.ssh/authorized_keys

# Or use emacs or vim or whatever editor you like best.  Whatever.  Shut up.

Now, the next time you log in as your user, it shouldn’t ask you for a password.

And once again, make sure the permissions are as restrictive as possible for this file.

# Once again logged into your server
sudo chmod 600 ~/.ssh/authorized_keys

But We Can Go Even More Secure

“But wait, shouldn’t we do a public key for our root user as well, so we don’t have to type that password either?” you ask. The answer is no. Actually, the most secure way is if your root user can’t even log in from the outside at all! We’re now going to edit the configuration for our ssh daemon (or, sshd for short) that controls how our server accepts ssh connections. Most configuration lives in the /etc directory, and this is no exception.

sudo nano /etc/ssh/sshd_config

Look for the line that says:

#PermitRootLogin yes

You’ll want to uncomment it and set that to “no.”

PermitRootLogin no

Side note: I always think it’s funny to add an additional line.

# PermitKennyLogin DANGER ZONE!

My wife, a teacher and not an avid sshd configurer, disagrees.

As extra steps, also change the following lines:

PasswordAuthentication no

# If you connect via IPv4:
AddressFamily inet
# If you connect via IPv6:
AddressFamily inet6

The first line turns off all password logins. Without this, your user account is still open to password login, which somebody can do even without your private key. The other lines shrink the amount of shenanigans you have to deal with by refusing to serve people who aren’t connecting like you. If you’re not going to ever connect via IPv6, why leave that open for some botnet to sniff around?

Lastly, once we’ve reconfigured a service, we need to reload it.

sudo systemctl reload sshd

And we should be good to go!

Moving In and Settling Down

We’re pretty much done with the security stuff. By now, you should be pretty much secure and feeling safe. Now we’re going to focus on turning this server into a pleasant place to work.

yum update && sudo yum upgrade

Watch as your server brings itself up to current.

ProTip: Yum Errors

If you get interrupted or, hypothetically, your dog jumps into your lap while this is happening and just manages to mash the correct keys to abort the upgrade without cleaning up, and you start seeing errors like “yum lock” or “sqlite3 database lock”, don’t panic.

Check to see if there’s still a yum process active.

ps aux | grep yum

If you see one that shouldn’t be active, try to kill it (take note of the process ID (PID) in the second column of the output from the above command).

kill <pid>
# Or, if you're feeling feisty and it's not working:
kill -9 <pid>

Willy is sorry he caused 90 minutes of frantically Googling error messages.

Sad Willy

Back To It

Now is a good time to install any packages you couldn’t be without: Zsh, oh-my-zsh, Ruby, Vim, and git are the first ones that come to mind. I’m going to show you just the first one, because there is one hiccup you might encounter. If you prefer Fish or some other shell, it should most likely be similar.

Installing Zsh

The first part should make sense.

sudo yum install zsh

Check to see where your executable lives.

where zsh
# /usr/bin/zsh

The important thing here is to make sure that this location is in your /etc/shells file, which is a list of the approved shells.

sudo nano /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/pwsh
/usr/bin/zsh # << Here's the one we're adding.

Once the zsh executable is approved, you can set your own default shell to zsh.

chsh -s $(where zsh)

Bonus: Bringing in Dot Files

If you’re like me, you’re probably reasonably proud of your slowly growing collection of “dot files.” But how do you get them from your computer onto the server, quickly, sanely, and repeatably? With Git. I found this article by Nicola Paolucci that I think is brilliant. We’re going to use a modified bare Git repository in our local home directory!

Setting Up

On your local machine:

git init --bare $HOME/.dotfiles
alias dot='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dot config --local status.showUntrackedFiles no
echo alias dot='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME' >> ~/.bashrc

We create a bare repo in our home directory to track our dot files, we create the dot command (or whatever you want to call it) which will function just like the git command, but just for our dotfiles. We configure it to only show us if our tracked files change, and then we save the dot command for later.

Now, all we have to do is start tracking some dot files!

dot status
dot add .zshrc
dot commit -m "Add zshrc"
dot remote add origin https://github.com/<you>/dotfiles.git
dot push -u origin master

You get all the benefits of Git! You can branch, edit, roll back, diff changes, and more.

Installing Onto Our Server

On the server, add your same dot command to your .zshrc file.

echo alias dot='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME' >> ~/.zshrc
. ~/.zshrc

If there are any stock files that might conflict with the dotfiles you’re about to pull in, either delete them or (better), copy them to a backup directory.

mkdir .dotfile-backup
mv .bashrc .dotfile-backup
mv .zshrc .dotfile-backup

Now we’re ready:

git clone --bare <dotfile repo url> $HOME/.dotfiles
echo ".dotfiles/" >> .gitignore
dot checkout
# Just in case:
dot config status.showUntrackedFiles no

And now your server should be on its way to being comfy, cozy, and functional!

Bonus Bonus: Message of the Day

I don’t know about you, but I believe that 98% of the reasons why I learned how to program were to make computers print out funny messages. To that end, I set up my Message of the Day accordingly.

sudo vim /etc/motd
==================================
You are a gentleman and a scholar.
==================================

If you can’t think of any one-liner affirmations to put in your MOTD, check out this list of compliments I curated for a twitter bot to pepper my brother with.

Now, whenever you log in, your server will greet you with an uplifting message! 😁

Wrap Up

I know there’s a lot more for me to learn in the system administration realm. I’m starting to stock up on books to read and videos to watch. Did I miss anything important? Do you have any extra protips? Any great resources for learning? Let me know about them! Thanks for reading!

Author: Ryan Palo | Tags: linux sysadmin security | Buy me a coffee Buy me a coffee

Like my stuff? Have questions or feedback for me? Want to mentor me or get my help with something? Get in touch! To stay updated, subscribe via RSS