May 2024
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
2728293031  

Categories

May 2024
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
2728293031  

CentOS 6 as a production LAMP server

LAMP (Linux, Apache, MySQL, PHP) server from the scratch in an virtualized environment. There are many articles, but neither of them cover all the required steps. So far after each I had to troubleshoot many issues that weren’t even mentioned in the articles and that involves lot of searching and playing around. One of many issues came from SElinux security contexts. That supports my personal believe that many people just turn SElinux off when run into troubles and don’t care much about security, since those how-tos were aimed for development / sandbox servers for just playing and not real production usage. Otherwise there would be a troubleshooting info included, or not?

My motivation to write down this article is because I think I reinvented the wheel many times and sometimes running into same issues again. So I decided to compile all the information all-together into this one bulletproof how-to, so i can return to it and improve it over time and to prevent repeating mistakes in future. I see the clear benefits from sharing my know-how here, because you will definitely come up with some comments and bright ideas which could help me to improve it over time and maybe introduce new features inside installation. Also writing it down forces me to think about the correct order of the commands and include every change as it will come.

I want to have a production, enterprise grade, free, fast and secure linux. In other words I want to keep SElinux enabled and I would like to have it as minimal as possible and install only what is necessary. In my case webserver is virtualized in VMware vSphere Hypervisor (ESXi) environment – at the time of writing of this article HP’s customized ver4.1 hosted on an HP ProLiant DL380 G7 rack server HW with 16GB RAM, 6x146GB SAS/6G 15000rpm drives in RAID10 array. I’m preparing for an upgrade to version 5.0 and will share an how-to do it after that.

The designation of this system is to run custom developed PHP/MySQL CRM server and accounting software. Therefore there is some specific optimization for my environment included and I will especially mention those steps trough this how-to.

The requirements for the target system state are these:

  • Free but enterprise-grade linux (done)
  • httpd (Apache) including configuration:
    • SSL support (done)
    • targeting to /home/webroot directory (needs improvement)
    • ServerName FDQN (needs insertion)
    • http auto redirecting to https (needs improvement)
  • PHP (done)
  • MySQL (done)
    • MySQL security hardening (needs improvement according to the script)
  • vsftpd (FTP sever) including SFTP support and passive mode transfers, MySQL login/password authentication (needs improvement, currently missing SFTP and passive mode support)
  • phpMyAdmin accessible trough HTTPS (needs improvement, allow access only trough https)
  • midnight commander accessible trough SSH (done)
  • SElinux enabled and security hardening performed, possibility to put the system into DMZ or directly on internet (done, needs testing)
  • firewall enabled and configured (done)
  • SSH enabled for remote administration via putty (done)
  • Optimized performance (needs improvement)
  • Scalable solution (done)
  • Easy to maintain, support, backup trough cron and restore (needs improvement – I will provide backup scripts and cron part)
  • Tested (needs more testing to claim it stable and secure)

Now let’s get to the thing:

I assume that you have up and running HW or virtual machine for this. I recommend you to allocate at least these specs. And remember – more is better!

  • Production server:
    • 4GB of RAM (8GB recommended)
    • Dual-Core CPU (Quad-Core recommended especially if server is running in virtual environment)
    • 40GB of storage (100GB recommended)
    • stable and fast internet connectivity with low latency and no lags
  • Development/testing server
    • 2GB RAM should be enough
    • 20GB of storage or more
    • internet connectivity
  • Sandbox with minimal configuration
    • 512MB RAM
    • 20GB of storage
    • internet connectivity

First we have to do a netinstall CentOS v6.0 x86_64. I’m always performing this with a netinstall and choose minimal installation during setup wizard. This allow me to always quickly download the actual version of CentOS in minutes and perform basic installation very fast. It usually takes around 15-45 minutes depending on HW and internet connection speed. My choice of 64-bit architecture comes from that system will operate above 4GB RAM and probably more over the time. I also believe that x64 is slightly improving performance but it depends on the application. My favorite Linux distros are RHEL, CentOS, Fedora and Debian, but last year I always ended up with CentOS since it’s free and equal to RHEL. I use RHEL for middle and large enterprise deployments with high-availability and standardization demands, where 3rd level vendor support is crucial. But for many and many deployments the CentOS is a perfect free solution that will get the job done.

  1. Download an iso image with netinstall version of CentOS 6.0 according to the server architecture (can be found at mirror.centos.org). I’ve used this one.
  2. Burn the iso onto CD/DVD, write it to USB drive, or mount it trough remote management of the server (iLO for HP or DRAC for Dell). If you use VMware you can mount it via VMware vSphere client.
  3. Setup your computer system’s BIOS to boot from media where you stored the image or use the boot menu feature. In VMware vCenter client, you can press Escape key during BIOS POST boot-up sequence – and you have to be very fast 😉 otherwise it will take more than one try…
  4. Boot into installation
  5. Select “Install or upgrade an existing system” (first choice) by just pressing enter.
  6. You can test you iso downloaded media if it is not corrupted. I prefer to test.
  7. Choose URL as Installation Method
  8. Configure TCP/IP (DHCP or manual)
  9. During URL setup you will have to enter the path to server, where installation files resides. This can be any from CentOS mirrors. I use this path, because it’s easy to remember: http://mirror.centos.org/centos/6.0/os/x86_64. Be sure to check the processor architecture, this one is for Intel/AMD 64 bit.
  10. The setup will download necessary files and proceed onto welcome screen
  11. Then you can proceed trough installation steps according to this article, starting up with step 5 and ending up with step 22 from that article and returning back here. No need to reinvent the wheel ;).
  12. That’s it, we have minimal CentOS 6 installation up and running
  13. Now we can proceed into LAMP installation and configuration:
  14. Be sure you’ve issued update command as a root user before continuing, it will update whole system and load patches since the iso initial release:
    yum -y update
  15. Install required packages (be sure to copy the whole line):
    yum -y install mc httpd mysql-server php php-mysql mysql php-mbstring php-pear php-pecl-apc php-xml php-imap yum-priorities php-pecl-zip php-gd php-ldap mod_ssl openssl vsftpd pam_mysql
  16. Install the support for EPEL repository:
    rpm -hUv http://download.fedora.redhat.com/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm
  17. Generate private key for Apache:
    openssl genrsa -out ca.key 1024
  18. Generate CSR for Apache:
    openssl req -new -key ca.key -out ca.csr
  19. Generate Self Signed Key:
    openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
  20. Copy the files to the correct locations:
    cp ca.crt /etc/pki/tls/certs
    cp ca.key /etc/pki/tls/private/ca.key
    cp ca.csr /etc/pki/tls/private/ca.csr
  21. Then we need to update the Apache SSL configuration file:
    vi /etc/httpd/conf.d/ssl.conf
    # Change the paths to match where the Key file is stored. If you've
    # used the method above it will be: 
    SSLCertificateFile /etc/pki/tls/certs/ca.crt 
    # Then set the correct path for the Certificate Key File a few lines 
    # below. If you've followed the instructions above it is:
    SSLCertificateKeyFile /etc/pki/tls/private/ca.key
    # Quit and save
  22. Enable MySQL daemon auto start-up with system:
    chkconfig mysqld on
  23. Start MySQL daemon:
    service mysqld start
  24. Connect locally to MySQL CLI:
    mysql -h 127.0.0.1 -u root
  25. List all users in MySQL. You should perform the root password setting for each line as described below:
    select user,host,password from mysql.user;
  26. Set the MySQL root password for localhost connections. Remember to use only sensible SAFE passwords! Most of people will use the same password for all three steps:
    set password for root@localhost=password('desiredmysqlrootpassword');
  27. Set the MySQL root password for 127.0.0.1 loopback connections:
    set password for root@'127.0.0.1'=password('desiredmysqlrootpassword');
  28. Set the MySQL root password for your hostname loopback connections. Remeber to replace hostname for the one you have entered during CentOS installation. In the future, you should perform this security step for each internet realm/domain name you will need to be accessed from:
    set password for root@'hostname'=password('desiredmysqlrootpassword');
  29. Delete anonymous users:
    delete from mysql.user where user='';
  30. Print the final MySQL user table:
    select user,host,password from mysql.user;
  31. Exit the MySQL CLI:
    exit;
  32. Start the MySQL CLI (be sure to use -h 127.0.0.1, because MySQL from CentOS rpm repository doesnt support IPv6, although localhost is mapped to an IPv6 address:
    mysql -h 127.0.0.1 -u root –p
    # Perform these commands onto MySQL CLI:
    CREATE DATABASE vsftpd; 
    USE vsftpd; 
    GRANT SELECT ON vsftpd.* TO 'vsftpd'@'127.0.0.1' IDENTIFIED BY 'vsftpdpassword'; 
    FLUSH PRIVILEGES;  
    CREATE TABLE `accounts` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `username` VARCHAR( 30 ) NOT NULL , `pass` VARCHAR( 50 ) NOT NULL , UNIQUE (`username`) ) ENGINE = MYISAM ;
    INSERT INTO accounts (username, pass) VALUES('ftpdesiredusername', md5('ftpdesiredpassword'));
    exit;
  33. Add vsftpd system account:
    useradd -G users -s /bin/false -d /home/vsftpd vsftpd
  34. Backup the vsftpd backup file content:
    cp -v /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf-orig
  35. Empty the config file:
    > /etc/vsftpd/vsftpd.conf
  36. Edit the vsftpd config file:
    vi /etc/vsftpd/vsftpd.conf
    # Enter this into vsftpd.conf file:
    
    # No ANONYMOUS users allowed
    anonymous_enable=NO
    # Allow 'local' users with WRITE permissions (0755)
    local_enable=YES
    write_enable=YES
    local_umask=022
    dirmessage_enable=YES
    xferlog_enable=YES
    # if you want to LOG vsftpd activity then uncomment this  log_ftp_protocol
    # log_ftp_protocol=YES
    connect_from_port_20=YES
    # uncomment xferlog_file and xferlog_std_format if you  DIDN'T use the line above
    # with log_ftp_protocol - it must be excluding each other
    # The name of log file when xferlog_enable=YES and  xferlog_std_format=YES
    # WARNING - changing this filename affects /etc/logrotate.d/vsftpd.log
    #xferlog_file=/var/log/xferlog
    #
    # xferlog_std_format Switches between logging into  vsftpd_log_file and xferlog_file files.
    # NO writes to vsftpd_log_file, YES to xferlog_file
    # xferlog_std_format=YES
    #
    # You may change the default value for timing out an idle session (in  seconds).
    #idle_session_timeout=600
    #
    # You may change the default value for timing out a data connection (in  seconds).
    #data_connection_timeout=120
    #
    # define a unique user on your system which the
    # ftp server can use as a totally isolated and unprivileged user.
    nopriv_user=vsftpd
    chroot_local_user=YES
    listen=YES
    # here we use the authentication module for vsftpd to check users name  and passw
    pam_service_name=vsftpd
    userlist_enable=YES
    tcp_wrappers=YES
    # here the vsftpd will allow the 'vsftpd' user to login into the 
    # '/home/vsftpd/$USER'  directory
    guest_enable=YES
    guest_username=vsftpd
    local_root=/home/vsftpd/$USER
    user_sub_token=$USER
    virtual_use_local_privs=YES
    user_config_dir=/etc/vsftpd/vsftpd_user_conf
  37. Create directory with user configuration files:
    mkdir /etc/vsftpd/vsftpd_user_conf
  38. Edit ftp user configuration:
    vi /etc/vsftpd/vsftpd_user_conf/ftpusername
    dirlist_enable=YES
    download_enable=YES
    # full path to the directory where 'ftpusername' will have access, change  to your needs
    local_root=/home/webroot
    write_enable=YES
  39. Create webroot directory:
    mkdir /home/webroot
  40. Allow full permissions for owner:
    chmod 700 /home/webroot
  41. Change owner:
    chown vsftpd:users /home/webroot
  42. Backup pam.d vsftpd authentication profile file:
    cp /etc/pam.d/vsftpd /etc/pam.d/vsftpd-orig
  43. Erase vsftpd pam.d auth config file:
    cat /dev/null > /etc/pam.d/vsftpd
  44. Edit file /etc/pam.d/vsftpd:
    vi /etc/pam.d/vsftpd
    # Insert the lines below into the file:
    
    #%PAM-1.0
     session       optional        pam_keyinit.so       force revoke
     auth required pam_mysql.so user=vsftpd passwd=vsftpdpassword  host=127.0.0.1 db=vsftpd table=accounts usercolumn=username   passwdcolumn=pass crypt=3
     account required pam_mysql.so user=vsftpd passwd=vsftpdpassword  host=127.0.0.1 db=vsftpd table=accounts usercolumn=username  passwdcolumn=pass crypt=3
  45. SElinux: Allow ftp daemon to connect to database to obtain user logins and passwords:
    setsebool -P ftpd_connect_db 1
  46. SElinux: Change security context to webroot directory:
    chcon -R -t public_content_rw_t /home/webroot
  47. SElinux: Change security context to webroot to be accessible for Apache
    setsebool -P allow_httpd_anon_write 1
  48. SElinux: Allow ftp daemon to access webroot
    setsebool -P ftp_home_dir 1
    setsebool -P allow_ftpd_anon_write 1
  49. Edit the firewall settings so you can get onto desired ports:
    vi /etc/sysconfig/iptables
    # You should end up with iptables file something like this. You will have to add lines if you wanna enable more ports, or on the contrary remove the ports not needed:
    
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [2:516]
    -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -p icmp -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT        # SSH
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT       # HTTP
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT # HTTPS
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT # FTP
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT # SFTP
    -A INPUT -j REJECT --reject-with icmp-host-prohibited # reject all other traffic (its important to have this line at the end of the port opening rules, otherwise firewall will drop the packets before they even got to the rule
    -A FORWARD -j REJECT --reject-with icmp-host-prohibited
    COMMIT
  50. Start Apache daemon:
    service httpd start
  51. Restart affected services:
    service iptables restart 
    service vsftpd restart
  52. Reboot the system
    reboot
  53. Test the apache/php

Resources used to develop this article:

http://techspotting.org/how-to-install-centos-6-linux-for-servers-desktops
http://www.chrisgountanis.com/technical/45-centos-netinstall.html
http://wiki.centos.org/HowTos/VirtualVsFtpd
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
http://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-autotasks-cron-configuring.html
http://www.server-world.info/en/note?os=CentOS_6&p=mysql

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>