Nginx, PHP on VPS
This is an update to the original post for setting up Apache, PHP on CentOS. Last year has been great and there is an abundance of vendors providing VPS on the cheap. My goto website for checking the latest on VPS vendors is www.lowendbox.com . For this post I went with a tiny 128MB VPS from www.ramnode.com . This server setup is for Cent OS 6.x with Nginx + PHP-FPM + MySQL. It describes how to setup a VPS (virtual private server) to run Nginx, PHP and MySQL on CentOS. The VPS uses a tiny amount of memory (total server memory is 128MB) and is running on CentOS 6.x. The intent is to setup a fully functional server that has been secured using iptables and configured to use Nginx, PHP-FPM and MySQL for production. It uses CentOS services to manage all the applications and is configured to use log rotation.
Here’s a quick overview of how to secure a VPS (virtual private server) running CentOS 6.x and configure Nginx and PHP5.
- Secure the server
- Setup nameserver
- Setup iptables
- Setup MySQL
- Setup PHP5
- Configure Nginx
- passwd root
- useradd myuser
- passwd myuser
- visudo
- Add line: myuser ALL=(ALL) ALL
- mkdir ~/.ssh
- cat id_rsa.pub » ~/.ssh/authorized_keys
- chmod 700 ~/.ssh
- chmod 600 ~/.ssh/authorized_keys
- vi /etc/ssh/sshd_config
- PermitRootLogin no
- PasswordAuthentication no
- sudo service sshd restart
- nmap -sV 123.45.67.89
In my original version I was running the nameserver on the VPS itself. It works perfectly fine, its secure and doesn’t use too much memory, but it does not provide the resiliency that you want for DNS. I started using Amazon Route53 and its cheap enough that I’ve switched to it completely for all my websites. Incase you’re still interested here are the instructions for nameserver setup on CentOS.
If you start with a barebones instance of CentOS or RedHat you must configure firewall rules using iptables to prevent your server from being compromised. Its surprising that without hours of spinning off a new VPS or Amazon EC2 instance you can see attempts to breakin to the server as root user via SSH. Its a good practice to disable SSH for root and also drop SSH session after N failed attempts. Also, close all ports except for the ones you plan on using like 22, 80, 443, etc. You can follow the steps outlined in IPTables for CentOS to setup firewall using iptables.
- Install MySQL 5.5 or 5.7 using yum
- Configure low memory settings in my.cnf
- Setup auto-start for mysqld service
- Secure the MySQL installation
# ------Installing MySQL 5.5 (low memory ~36M)------
sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
sudo rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm
suo yum install mysql55w mysql55w-server
sudo vi /etc/my.cnf
sudo service mysqld start
sudo chkconfig --level 235 mysqld on
/usr/bin/mysqlsecureinstallation
# ------Installing MySQL 5.7 (memory usage ~124M)------
wget http://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm
sudo yum localinstall mysql57-community-release-el6-11.noarch.rpm
sudo yum repolist enabled | grep "mysql.*-community.*"
sudo yum install mysql-community-server
sudo vi /etc/my.cnf
sudo service mysqld start
sudo chkconfig --level 235 mysqld on
# -- check for errors in /var/log/messages
# -- check for errors and temp root password in /var/log/mysqld.log
/usr/bin/mysqlsecureinstallation
mysql -u root -p
show plugins;
uninstall plugin validate_password;
set password for 'root'@'localhost' = 'new_pass'
# File: /etc/my.cnf
# --- Add config lines after [mysql_safe] block
# BSH: low memory for MySQL 5.5 (~36M)
character-set-server=utf8
collation-server=utf8_general_ci
# BSH: low memory for MySQL 5.7 (~124M)
explicit_defaults_for_timestamp = TRUE
table_open_cache=4
query_cache_limit=256K
query_cache_size=4M
max_allowed_packet=1M
sort_buffer_size=64K
read_buffer_size=256K
thread_stack=64K
innodb_buffer_pool_size = 56M
innodb_flush_neighbors=0
innodb_flush_log_at_trx_commit=2
character-set-server=utf8
collation-server=utf8_general_ci
- yum install php php-fpm php-common php-mysql php-pdo php-pecl-apc php-cli php-mcrypt php-xml php-gd php-mbstring
- vi /etc/php.ini
expose_php = Off
display_errors = Off
session.name = OKID
session.cookie_httponly = 1
- chkconfig –levels 235 php-fpm on
- service php-fpm start
- Install nginx yum repository
- vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=0
- yum –enablerepo=nginx install nginx
- chkconfig –list httpd
- chkconfig –level 3 httpd off
- chkconfig –level 3 nginx on
- service nginx start
- vi /usr/share/nginx/html/index.html
- vi /etc/nginx/nginx.conf
- vi /etc/nginx/conf.d/default.conf
- nginx log rotation - /etc/logrotate.d/nginx
- edit config: vi /etc/logrotate.d/nginx
- test run: /etc/cron.daily/logrotate
#FILE: /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
server_tokens off;
include /etc/nginx/conf.d/*.conf;
}
#FILE: /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost mydomain.com www.mydomain.com;
root /usr/share/nginx/html;
#BSH: enable etag
etag on;
location / {
index index.html index.php;
#BSH: redirect all non file, non dir requests to index.php
try_files $uri $uri/ /index.php;
}
#BSH: ensure all /login requests use https
location ^~ /login {
return 301 https://$host$request_uri;
}
#BSH: ensure all /app requests use https
location ^~ /app {
return 301 https://$host$request_uri;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# -----pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000-----
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name localhost mydomain.com www.mydomain.com;
root /usr/share/nginx/html;
#BSH: set ssl cert properties
keepalive_timeout 70;
ssl_certificate /etc/ssl/certs/www_mydomain_com.pem;
ssl_certificate_key /etc/ssl/certs/www_mydomain_com_private.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
...
}
- cd /etc/init.d
- vi named
- chkconfig –list
- chkconfig –level 235 named on
- chkconfig –level 3 nginx on
- chkconfig –level 3 httpd off