This tutorial is how to make a Web Server under Debian 6 using Nginx web server, MySQL as a database server, PHP-FPM as a fastCGI server, APC as an optcode cache and Varnish as a caching proxy to optimize a website using wordpress.
I have tried this method using Debian 6.0.5 32BIT on XEN VPS with 512 Memory.
Step 1: Adding main debian repos
Because i’m using idROOT as Indonesia VPS Provider, so i’m using Indonesian repository which is located at Kambing.ui.ac.id
1 2 3 |
deb http://kambing.ui.ac.id/debian/ squeeze main contrib non-free deb http://kambing.ui.ac.id/debian/ squeeze-updates main contrib non-free deb http://kambing.ui.ac.id/debian-security/ squeeze/updates main contrib non-free |
Step 2: Adding dot-deb repo
1 2 3 4 |
# echo deb http://packages.dotdeb.org stable all >> /etc/apt/sources.list # echo deb-src http://packages.dotdeb.org stable all >> /etc/apt/sources.list # wget http://www.dotdeb.org/dotdeb.gpg # cat dotdeb.gpg | apt-key add - |
Step 3: Update and adding base software
1 2 |
# apt-get update && apt-get upgrade # apt-get install nano sudo curl lsb-release |
Step 4: Adding Varnish repo and Install Varnish
1 2 3 4 |
# curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add - # echo "deb http://repo.varnish-cache.org/debian/ $(lsb_release -s -c) varnish-3.0" >> /etc/apt/sources.list.d/varnish.list # apt-get update # apt-get install varnish |
Step 5: Adding a system user and Add user to sudo
1 2 |
# adduser [USER] # visudo |
find: root ALL and then add this line below : [USER] ALL=(ALL) ALL
Step 5: Installing Software
1 |
# apt-get install nginx mysql-server mysql-client memcached php5 php-apc php-auth php-net-smtp php-net-socket php-pear php5-curl php5-gd php5-mcrypt php5-mysql php5-fpm php5-memcached php5-tidy |
Step 6: Configuring MySql
1 2 |
# mv /etc/mysql/my.cnf /etc/mysql/my.cnf.bak # nano /etc/mysql/my.cnf |
Insert this code into /etc/mysql/my.cnf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = -5 open_files_limit = 8192 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp skip-external-locking bind-address = 127.0.0.1 key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 myisam-recover = BACKUP query_cache_limit = 4M query_cache_size = 250M query_cache_type = 1 query_prealloc_size = 65K query_alloc_block_size = 128K tmp_table_size = 32M wait_timeout=500 expire_logs_days = 10 max_binlog_size = 100M [mysqldump] quick quote-names max_allowed_packet = 16M [mysql] no-auto-rehash # faster start of mysql but no tab completition [isamchk] key_buffer = 16M sort_buffer = 8M read_buffer = 4M write_buffer = 4M !includedir /etc/mysql/conf.d/ |
Step 6: Configuring nginx
1 2 |
# mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak # nano /etc/nginx/nginx.conf |
Insert this code into /etc/nginx/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
user www-data; worker_processes 1; pid /var/run/nginx.pid; events { use epoll; worker_connections 512; multi_accept on; } http { include /etc/nginx/mime.types; default_type application/octet-stream; error_log /var/log/nginx/error.log; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 3; server_tokens off; access_log off; client_max_body_size 32m; client_body_timeout 60; client_header_timeout 60; send_timeout 60; reset_timedout_connection on; gzip on; gzip_disable "MSIE [1-6].(?!.*SV1)"; gzip_vary on; gzip_static on; gzip_proxied any; gzip_comp_level 9; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } |
1 2 3 |
# mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak # /home/[USER]/logs/ # nano /etc/nginx/sites-available/default |
Insert this code into /etc/nginx/sites-available/default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
server { listen 8080; server_name www.asep.id asep.us; access_log /home/asep/logs/access.log; error_log /home/asep/logs/error.log; root /home/asep/www; location / { index index.php index.html index.htm; try_files $uri $uri/ /index.php?$args; } # Add trailing slash to */wp-admin requests. rewrite /wp-admin$ $scheme://$host$uri/ permanent; # Directives to send expires headers and turn off 404 error logging. location ~* .(js|css|png|jpg|jpeg|gif|ico)$ { expires 24h; log_not_found off; } # Pass uploaded files to wp-includes/ms-files.php. rewrite /files/$ /<a href="http://www.info-vijesti.com/">index</a>.php last; location ~ .php$ { include fastcgi_params; if ($uri !~ "^/images/") { fastcgi_pass 127.0.0.1:9000; } fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_intercept_errors on; fastcgi_ignore_client_abort off; fastcgi_connect_timeout 60; fastcgi_send_timeout 360; fastcgi_read_timeout 360; fastcgi_buffer_size 128k; fastcgi_buffers 8 256k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /home/asep/www$fastcgi_script_name; } location ~ /.htaccess { deny all; log_not_found off; access_log off; } location ~ /.htpasswd { deny all; log_not_found off; access_log off; } location = /favicon.ico { allow all; log_not_found off; access_log off; } location = /robots.txt { allow <a href="http://www.youtube.com/watch?v=gzZeajtHiiw">all</a>; log_not_found off; access_log off; } } |
Step 7: Fix CGI Path Info
1 |
# nano /etc/php5/fpm/php.ini |
find cgi.fix_pathinfo and Uncomment the command by removing the ; in front and replace the defauly 1 with a 0!
Step 8: Configuring PHP5-FPM
1 2 |
# mv /etc/php5/fpm/php-fpm.conf /etc/php5/fpm/php-fpm.conf.bak # nano /etc/php5/fpm/php-fpm.conf |
Insert this code into /etc/php5/fpm/php-fpm.conf
1 2 3 4 5 6 7 8 9 |
[global] pid = /var/run/php5-fpm.pid error_log = /var/log/php5-fpm.log <a href="http://www.logobox.cz">log</a>_level = notice emergency_restart_threshold = 5 emergency_restart_interval = 2 process_control_timeout = 2 daemonize = yes include=/etc/php5/fpm/pool.d/*.conf |
1 2 |
# mv /etc/php5/fpm/pool.d/www.conf /etc/php5/fpm/pool.d/www.conf.bak # nano /etc/php5/fpm/pool.d/www.conf |
Insert this code into /etc/php5/fpm/pool.d/www.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
[www] ;prefix = /path/to/pools/$pool listen = 127.0.0.1:9000 listen.backlog = -1 listen.allowed_clients = 127.0.0.1 listen.owner = [USER] listen.group = [USER] listen.mode = 0666 user = [USER] group = [USER] pm = dynamic pm.max_children = 15 pm.start_servers = 5 pm.min_spare_servers = 2 pm.max_spare_servers = 10 pm.max_requests = 0 pm.status_path = /fpmstatus ping.path = /ping ping.response = pong request_terminate_timeout = 10 request_slowlog_timeout = 10 slowlog = /var/log/$pool.log.slow ;rlimit_files = 1024 ;rlimit_core = 0 ;chroot = ;chdir = / catch_workers_output = yes env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f kang@asep.us php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on php_admin_value[memory_limit] = 32M php_admin_value[date.timezone] = Asia/Jakarta php_value[upload_max_filesize] = 10M php_value[max_execution_time] = 120 |
Step 9: Configuring Varnish
1 2 |
# mv /etc/default/varnish /etc/varnish/default.bak # nano /etc/default/varnish |
Insert this code into /etc/default/varnish
1 2 3 4 5 6 7 8 |
START=yes NFILES=131072 MEMLOCK=82000 DAEMON_OPTS="-a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,1G" |
1 2 |
mv /etc/varnish/default.vcl /etc/varnish/default.vcl.bak nano /etc/varnish/default.vcl |
Insert this code into /etc/varnish/default.vcl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
backend default { .host = "localhost"; .port = "8080"; } acl purge { "localhost"; } sub vcl_recv { if (req.request == "PURGE") { if (!client.ip ~ purge) { error 405 "Not allowed."; } return(lookup); } if (req.url ~ "^/$") { unset req.http.cookie; } } sub vcl_hit { if (req.request == "PURGE") { set obj.ttl = 0s; error 200 "Purged."; } } sub vcl_miss { if (req.request == "PURGE") { error 404 "Not in cache."; } if (!(req.url ~ "wp-(login|admin)")) { unset req.http.cookie; } if (req.url ~ "^/[^?]+.(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)(?.|)$") { unset req.http.cookie; set req.url = regsub(req.url, "?.$", ""); } if (req.url ~ "^/$") { unset req.http.cookie; } } sub vcl_fetch { if (req.url ~ "^/$") { unset beresp.http.set-cookie; } if (!(req.url ~ "wp-(login|admin)")) { unset beresp.http.set-cookie; }} |
step 10: Securing VPS
Securing SSH
1 |
# nano /etc/ssh/sshd_config |
–find: PermitRootLogin yes
–change to: PermitRootLogin no
–find: X11Forwarding yes
–change to: X11Forwarding no
–find: Port 22
–change to: 7766
–add to end: UseDNS no
Restart SSH
1 |
# servive sshd restart |
Installing IPTABLES
1 |
# apt-get install iptables |
// Show what is loaded in our firewall
1 |
# iptables -L |
// Flush everything we have in our firewall
1 |
# iptables -F |
// Allow established sessions
1 |
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT |
// Allow services
1 2 3 4 5 |
iptables -A INPUT -p tcp --dport 7766 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 8080 -j ACCEPT iptables -A INPUT -p tcp --dport 9000 -j ACCEPT iptables -A INPUT -p tcp --dport 12000:12100 -j ACCEPT |
// End iptables by blocking everything that we didn’t explicitly allowed earlier
1 |
iptables -A INPUT -j DROP |
// backup iptables to a file
1 |
iptables-save > /home/[USER]/iptables.rules |
Making sure iptables rules are reloaded on reboot
1 |
# nano /etc/network/if-up.d/iptables |
Insert this code
1 2 |
#!/bin/sh iptables-restore < /home/[USER]/iptables.rules |
1 |
# chmod +x /etc/network/if-up.d/iptables |
Restartig our services
1 2 3 4 5 |
# service mysql restart # service memcached restart # service varnish restart # service nginx restart # /etc/init.d/php5-fpm restart |
Reference:
http://www.axelsegebrecht.com/how-to/install-nginx-apc-varnish-wordpress-and-w3-cache-128mb-vps/
http://library.linode.com/lemp-guides/debian-6-squeeze
http://www.farinspace.com/wordpress-nginx-rewrite-rules/