Saturday, April 26, 2014

What should I do after ordering a CentOS 6.5 server?

Okay, so I know how to do this on a Debian 7 box. However, I've never done server setup on a CentOS machine, until now. Here's a post I did on how to setup a Debian 7 box: http://oneqonea.blogspot.com/2013/04/how-do-i-set-up-next-generation.html. This post is based on that one. I'm following the other post as a conceptual guide and using this one to capture my translation process.

ssh root@youripaddress

Changing the root user's password was the same between Debian and CentOS:
passwd

Instead of "adduser admin" it was "useradd youruser". In CentOS you need to follow "useradd youruser" with "passwd youruser" Reference: https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-users-add.html Also note this is a decent article too: https://www.digitalocean.com/community/articles/initial-server-setup-with-centos-6

visudo process was the same between Debian and CentOS (i.e. making youruser have sudo privileges):
youruser    ALL=(ALL)    ALL

Updating the ssh port number was the same between Debian and CentOS. However, Debian has PasswordAuthentication commented out (set to no) while CentOS defaults to PasswordAuthentication yes.

vim /etc/ssh/sshd_config
"Update your port number to something unique such as 7919" Save the file (ZZ).

How to restart the ssh service varied slightly: http://www.cyberciti.biz/faq/howto-restart-ssh/. The CentOS way is: /etc/init.d/sshd restart

In terms of how to configure iptables. Things were different. I implemented the same rules but the steps were as follows (inspired by http://wiki.centos.org/HowTos/Network/IPTables):

  1. I logged in as the root user
  2. I created a file called myfirewall and gave it the execute bit: chmod +x myfirewall
  3. vim myfirewall and copy and paste (with ssh port edits that sync with /etc/ssh/sshd_config edits) the following text into it and then save and close: http://oneqonea.blogspot.com/2014/04/myfirewall-file.html
  4. As the root user run: ./myfirewall Then, boom. You're locked and loaded.
    1. Clears rules then resets them. This executes the iptables init script, which runs /sbin/iptables-save and writes the current iptables configuration to /etc/sysconfig/iptables. Upon reboot, the iptables init script reapplies the rules saved in /etc/sysconfig/iptables by using the /sbin/iptables-restore command.
If you're still logged in as root, instead of "aptidude update" run "yum update" (add sudo if you're not root). Reference: https://www.centos.org/forums/viewtopic.php?t=39652

Okay so the next steps vary slightly depending on whether or not we're setting up an app/web server or a database server. App/web gets apache and php. Database gets mysql.

Here's good article for getting Apache, PHP, and MySQL installed: https://www.digitalocean.com/community/articles/how-to-install-linux-apache-mysql-php-lamp-stack-on-centos-6. Install the right software given the type of machine you're setting up. Note that if you're setting up an app server that runs an app that connects to a mysql database, that you'll need to install mysql on the app server even if you're connecting to a remote mysql database (for release purposes).

App server command brief:
yum install httpd # Already installed
yum install mysql # For release purposes needed on app server
yum install php php-mysql # The mother ship
yum install php-gd # Needed for app server image processing functions to work

Note, after you install MySQL run: service mysqld start

By default PHP Version 5.3.3 is installed. I need newer than that. I followed this tutorial: http://webees.me/how-to-install-php-5-4-and-mysql-5-5-in-centos-6-4-via-yum/

By default MySQL Server Version 5.1.73 is installed. I need newer than that. I followed this tutorial: http://webees.me/how-to-install-php-5-4-and-mysql-5-5-in-centos-6-4-via-yum/ (my app requires 5.5 or higher for utf8 character reasons).

Okay, so if you're setting up a server that uses PHP's imagecreatefromjpeg function then you need gd. Since the php we just installed doesn't have gd we run the following command to add it:

yum --enablerepo=epel,remi,rpmforge install gd gd-devel php-gd
/etc/init.d/httpd restart

After doing all that I setup ssh keys (and optionally turn password access off) for both machines. I followed this tutorial: http://wiki.centos.org/HowTos/Network/SecuringSSH#head-9c5717fe7f9bb26332c9d67571200f8c1e4324bc

Then I installed git via: yum install git

Then I create a key-pair on the server:
ssh-keygen -t rsa -C "your_email@example.com"

Save in default location and skip the passphrase.

Now add your id_rsa.pub file content to Bitbucket as a deploy key: https://bitbucket.org/acctowner/projectname/admin/deploy-keys. I like to label my key using machine IP address. To get key:

cat ~/.ssh/id_rsa.pub

After doing that I git cloned project source files from their Bitbucket home to a folder within admin's home directory:

git clone git@bitbucket.org:acctowner/projectname.git

Then I installed a wild card ssl cert by loading the .crt and .key files to the remote machine like so: http://wiki.centos.org/HowTos/Https. Note that I skipped part three and didn't do anything special with virtual hosts. Command recap:
$ sudo yum install mod_ssl openssl
$ exit
$ scp -P 1234 ~/your/cert/on/your/comp/STAR_domain_com/STAR_domain_com.crt root@youripaddress:STAR_domain_com.crt
$ scp -P 1234 ~/your/cert/on/your/comp/STAR_domain_com/STAR_domain_com.key root@youripaddress:STAR_domain_com.key
$ ssh -p 1234 root@youripaddress
$ mv STAR_domain_com.crt /etc/pki/tls/certs/STAR_domain_com.crt
$ mv STAR_domain_com.key /etc/pki/tls/private/STAR_domain_com.key
$ vim +/SSLCertificateFile /etc/httpd/conf.d/ssl.conf # Update certificate paths
$ /etc/init.d/httpd restart

Now on to setting up the apache hosting environment:
sudo vim /etc/httpd/conf/httpd.conf

#DocumentRoot "/var/www/html"
DocumentRoot "/home/youruser/yourproject/www"

#<Directory "/var/www/html">
<Directory "/home/youruser/yourproject/www">

# For CodeIgniter, faster than .htaccess file
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]

sudo /etc/init.d/httpd restart

You will experience a 403 Forbidden error on refresh.

I found the steps I needed to follow here: https://drupal.org/node/244924
$ cd /home/youruser/yourproject
$ sudo chown -R youruser:apache .
$ sudo find . -type d -exec chmod u=rwx,g=rx,o= '{}' \;
$ sudo find . -type f -exec chmod u=rw,g=r,o= '{}' \;
$ sudo chmod 711 /home/youruser

Then 770 the dirs you need apache to be able to write to (temp, runtime, logs, etc).

chmod 770 yourproject/application/logs/
To enable CodeIgniter app to be able to write files to the app's default log dir.

chmod 770 yourproject/application/runtime
chmod 770 yourproject/application/runtime/img
chmod 770 yourproject/www/images/local_cdn
A reminder for myself to enable app specific write dirs.

sudo vim /etc/php.ini

Then update php's memory limit from its default of 128M to something bigger like so:
sudo vim /etc/php.ini
;memory_limit = 128M
;
;johnerck says: free -m prints "Mem: free 6290" so I figure we can alloc 4000MB
memory_limit = 4000M

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
;upload_max_filesize = 2M
upload_max_filesize = 100M

; http://php.net/post-max-size
;post_max_size = 8M
post_max_size = 100M

;error_log = php_errors.log
error_log = /home/youruser/php_error.log

Save the file (ZZ).

Now create the log file we just referenced in our php.ini edits:
vim /home/youruser/php_error.log
/*Add some content such as "php_error.log" and save (ZZ)*/
Make sure the log file just created is 664 and "sudo chown youruser:apache php_error.log"

sudo /etc/init.d/httpd restart

Ok, we are for sure linked in with php errors!! It's been tested!! For example, if there is a syntax error in your php code, such as a missing semicolon, php will log the error to /home/youruser/php_error.log. You can tail -f /home/youruser/php_error.log and then refresh the browser on a page with a known missing semicolon and you will see the error write to the terminal (and filesystem). This is great.

If you're hosting a CodeIgniter app like I am then you'll want to check the following:
Make sure $config['log_threshold'] is >= 1 (so that it does actually log to the file system).

Note that in addition to the php error logs we just finished setting up, Apache also has an error log that can be viewed here: sudo cat /var/log/httpd/error_log

Next I needed to setup clitools and deploy with secure config file to fix the following error message from our API codebase: "The application environment is not set correctly.". I installed clitools, filled out the _*.yaml files and then ran a clitools/releaseto production.

I then needed to get the database server further setup:
http://www.rackspace.com/knowledge_center/article/installing-mysql-server-on-centos

Where they were doing "'demouser'@'localhost'" I was doing "'myuser'@'%'" so it can access remotely. I like this guy's recommendation regarding performance and iptables: http://www.noelherrick.com/blog/creating-users-granting-permissions-in-mysql

For a simple localhost setup you'll likely run the following commands in this order:

mysql -uroot -p

SELECT User, Host, Password FROM mysql.user; -- Shows current state

CREATE DATABASE demodb;

INSERT INTO mysql.user (User,Host,Password) VALUES('demodbuser','localhost',PASSWORD('yourfancypassword'));

FLUSH PRIVILEGES;

SELECT User, Host, Password FROM mysql.user; -- Shows current state

GRANT ALL PRIVILEGES ON demodb.* to demodbuser@localhost;

FLUSH PRIVILEGES;

SHOW GRANTS FOR 'demodbuser'@'localhost'; -- Shows current state

Now I'm going to see if I can get the two boxes to talk to each other over the SoftLayer private network. Okay, yup, they're talking.

What does my default CentOS iptables firewall file look like?

CentOS myfirewall template file:
#!/bin/bash
#
# iptables example configuration script
#
# Flush all current rules from iptables
#
iptables -F
#
#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# 
#
#  Accepts all established inbound connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 
# 
#  Allows all outbound traffic
#  You can modify this to only allow certain traffic
iptables -A OUTPUT -j ACCEPT
# 
# 
# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 
# 
#  Allows SSH connections
#
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
#
iptables -A INPUT -p tcp -m state --state NEW --dport 7921 -j ACCEPT
# 
# 
# Allow ping
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# 
# 
# log iptables denied calls
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# 
# 
# Reject all other inbound - default deny unless explicitly allowed policy
iptables -A INPUT -j REJECT
iptables -A FORWARD -j REJECT
#
#
# Save settings
#
/sbin/service iptables save
#
# List rules
#
iptables -L -v
#

About Me

My photo
I code. I figured I should start a blog that keeps track of the many questions and answers that are asked and answered along the way. The name of my blog is "One Q, One A". The name describes the format. When searching for an answer to a problem, I typically have to visit more than one site to get enough information to solve the issue at hand. I always end up on stackoverflow.com, quora.com, random blogs, etc before the answer is obtained. In my blog, each post will consist of one question and one answer. All the noise encountered along the way will be omitted.