Berikut merupakan cara untuk menginstall webserver Nginx dengan PHP-FPM dan Userdir. Sebelum memulai pastikan Anda sudah memilki 1 server CentOS dengan RAM minimal 1GB.
Instalasi Nginx #
1. Tambahkan Repository Nginx #
Untuk menambahkan repository resmi Nginx, ikuti panduan dari situs resmi https://nginx.org/en/linux_packages.html
Pastikan Anda memilih panduan sesuai dengan distribusi Linux yang digunakan (misalnya CentOS, RHEL, Ubuntu, atau Debian). Panduan tersebut mencakup langkah-langkah untuk:
- Menambahkan file repository Nginx.
- Mengimpor GPG key untuk verifikasi paket.
- Memilih antara versi stable atau mainline.
2. Instalasi Nginx #
Untuk CentOS/RHEL, jalankan perintah berikut:
yum -y install nginx
3. Instalasi Nginx (untuk Ubuntu/Debian) #
Jika Anda menggunakan Ubuntu atau Debian, jalankan:
apt -y install nginx \
libnginx-mod-http-auth-pam \
libnginx-mod-http-brotli-filter \
libnginx-mod-http-brotli-static \
libnginx-mod-http-cache-purge \
libnginx-mod-http-dav-ext \
libnginx-mod-http-echo \
libnginx-mod-http-fancyindex \
libnginx-mod-http-geoip \
libnginx-mod-http-geoip2 \
libnginx-mod-http-headers-more-filter \
libnginx-mod-http-image-filter \
libnginx-mod-http-lua \
libnginx-mod-http-ndk \
libnginx-mod-http-ndk-dev \
libnginx-mod-http-perl \
libnginx-mod-http-subs-filter \
libnginx-mod-http-uploadprogress \
libnginx-mod-http-upstream-fair \
libnginx-mod-http-xslt-filter \
libnginx-mod-mail \
libnginx-mod-nchan \
libnginx-mod-rtmp \
libnginx-mod-stream \
libnginx-mod-stream-geoip \
libnginx-mod-stream-geoip2
4. Buat User web1
#
Buat user baru bernama web1
useradd -m web1
5. Aktifkan Fitur Userdir #
Edit file konfigurasi Nginx, misalnya /etc/nginx/conf.d/default.conf
, dan tambahkan blok berikut ke dalam bagian server { ... }
:
location ~ ^/~([^/]+)(/.*)?$ {
alias /home/$1/public_html$2;
index index.html index.htm;
autoindex on;
}
Pastikan direktori
/home/USERNAME/public_html
memiliki permission yang tepat agar bisa diakses oleh Nginx.
Instalasi PHP #
1. Tambahkan Repository Remi #
Untuk mendapatkan versi PHP yang lebih lengkap dan terbaru, instal repo Remi terlebih dahulu:
yum -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
2. Instal PHP 7.4 dan Modul yang Dibutuhkan #
Setelah repo Remi terpasang, instal PHP 7.4 beserta modul-modul yang umum digunakan:
yum -y install \
php74.x86_64 \
php74-php-bcmath.x86_64 \
php74-php-brotli.x86_64 \
php74-php-fpm.x86_64 \
php74-php-gd.x86_64 \
php74-php-imap.x86_64 \
php74-php-intl.x86_64 \
php74-php-ioncube-loader.x86_64 \
php74-php-json.x86_64 \
php74-php-mbstring.x86_64 \
php74-php-mysqlnd.x86_64 \
php74-php-opcache.x86_64 \
php74-php-pecl-imagick.x86_64 \
php74-php-pecl-zip.x86_64 \
php74-php-sodium.x86_64 \
php74-php-xml.x86_64 \
php74-php-xmlrpc.x86_64
3. Buat Pool FPM untuk User web1
#
Buat file konfigurasi baru untuk PHP-FPM pool web1
:
nano /etc/opt/remi/php74/php-fpm.d/web1.conf
Isi file tersebut dengan konfigurasi berikut:
[web1]
user = web1
group = web1
catch_workers_output = yes
chdir = /home/web1/public_html
listen = /var/opt/remi/php74/run/php-fpm/web1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
listen.acl_users = web1,www-data
listen.allowed_clients = 127.0.0.1
listen.backlog = 32768
request_slowlog_timeout = 5s
slowlog = /home/web1/logs/php.slow.log
pm = ondemand
pm.max_children = 50
pm.max_requests = 200
pm.process_idle_timeout = 10s
pm.start_servers = 1
pm.max_spare_servers = 1
pm.min_spare_servers = 1
pm.status_path = /status
ping.path = /ping
request_terminate_timeout = 300
security.limit_extensions = .phtml .php .php3 .php4 .php5 .php6 .php7 .php8
; PHP configuration
php_admin_flag[allow_url_fopen] = on
php_admin_flag[log_errors] = on
; abused php functions
; php_admin_value[disable_functions] = show_source, system, shell_exec, passthru, exec, popen, proc_open
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_value[short_open_tag] = on
php_admin_value[sys_temp_dir] = "/home/web1/tmp"
php_admin_value[upload_tmp_dir] = "/home/web1/tmp"
php_admin_value[max_input_vars] = 10000
php_admin_value[doc_root] = "/home/web1/public_html"
php_admin_value[error_log] = /home/web1/logs/php.error.log
php_value[error_reporting] = E_ALL & ~E_NOTICE
php_value[max_execution_time] = 300
php_value[max_input_time] = 300
php_value[memory_limit] = 512M
;php_value[open_basedir] = "/home/web1/:/tmp/:/var/www/:/usr/share/php/:/var/run/nginx-cache/:/dev/urandom:/dev/shm:/var/lib/php/sessions/"
php_value[session.save_handler] = files
php_value[session.save_path] = "/home/web1/tmp"
php_value[date.timezone] = "Asia/Jakarta"
php_value[post_max_size] = 256M
php_value[upload_max_filesize] = 128M
env[TMPDIR] = "/home/web1/tmp"
Konfigurasi Virtual Host #
1. Login sebagai User web1
#
su - web1
2. Buat Direktori Publik dan Atur Permission #
Jalankan perintah berikut sebagai user web1
untuk membuat direktori yang dibutuhkan:
mkdir -p ~/public_html ~/logs ~/tmp
chmod 711 /home/web1/
Penjelasan:
public_html
— untuk menyimpan file website.logs
— untuk menyimpan file log PHP.tmp
— untuk keperluan temporary file (upload, session, dsb).chmod 711 /home/web1/
— memastikan Nginx dapat mengakses direktori home, dan membatasi isi direktori supaya tidak bisa dilihat oleh pengguna lain.
3. Buat File index.php
untuk Pengujian
#
nano ~/public_html/index.php
Isi dengan:
<?php phpinfo(); ?>
4. Buat Konfigurasi Virtual Host Nginx #
Buat file baru:
nano /etc/nginx/conf.d/web1.conf
Isi dengan konfigurasi berikut:
server {
listen 80;
server_name web1.example.com;
root /home/web1/public_html;
index "index.html" "index.cgi" "index.pl" "index.php" "index.xhtml" "index.htm" "index.shtml";
client_max_body_size 128m;
access_log /var/log/nginx/web1.access.log rt_cache;
error_log /var/log/nginx/web1.error.log;
disable_symlinks if_not_owner from=/home/web1/public_html;
# SEO-friendly permalink fallback
set $sef_entry_point /;
if ($uri ~* "^/") {
set $sef_entry_point "/index.php?$args";
}
location @wpt_permalinks_fallback {
try_files $uri $sef_entry_point;
}
error_page 404 = @wpt_permalinks_fallback;
error_page 405 = @wpt_permalinks_fallback;
include location.conf;
location ~ \.php(/.*)?$ {
try_files $uri $fastcgi_script_name =404;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:/var/opt/remi/php74/run/php-fpm/web1.sock;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 32 32k;
include /etc/nginx/fastcgi.conf;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
5. Buat File fastcgi.conf
(Jika Belum Ada)
#
Jika file /etc/nginx/fastcgi.conf
belum tersedia (misalnya di beberapa distribusi minimalis), Anda dapat membuatnya secara manual:
nano /etc/nginx/fastcgi.conf
Isi dengan konfigurasi berikut:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
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_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# Untuk PHP dengan opsi build --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
# To fix CGI application vulnerability - https://httpoxy.org
fastcgi_param HTTP_PROXY "";
# Memastikan HTTP_HOST tetap terbaca saat menggunakan HTTP/3 (QUIC)
fastcgi_param HTTP_HOST $host;
6. Buat File location.conf
#
File ini berisi konfigurasi lokasi tambahan untuk optimasi cache, keamanan, dan dukungan Let’s Encrypt. Jalankan perintah berikut:
nano /etc/nginx/location.conf
Isi dengan konfigurasi berikut:
# Basic locations files
location = /favicon.ico {
try_files /wp-content/uploads/fbrfg/favicon.ico $uri $uri/ /index.php?$args @empty_gif;
access_log off;
log_not_found off;
expires max;
}
# Dummy GIF response
location @empty_gif {
empty_gif;
}
# Cache untuk file statis
location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|woff2|ttf|m4a|mp4|rss|atom|jpe?g|gif|cur|heic|png|tiff|ico|webm|mp3|aac|tgz|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|swf|webp|json|webmanifest|cast)$ {
more_set_headers 'Access-Control-Allow-Origin: *';
more_set_headers 'Cache-Control: public, no-transform';
access_log off;
log_not_found off;
expires max;
}
# Cache untuk CSS & JS
location ~* \.(css(\.map)?|js(\.map)?)$ {
more_set_headers 'Access-Control-Allow-Origin: *';
more_set_headers 'Cache-Control: public, no-transform';
access_log off;
log_not_found off;
expires 1y;
}
# Tolak akses file tersembunyi (kecuali .well-known)
location ~ /\.(?!well-known\/) {
deny all;
}
# Validasi Let's Encrypt
location /.well-known/acme-challenge/ {
alias /var/www/html/.well-known/acme-challenge/;
allow all;
auth_basic off;
}
# Private Prefetch Proxy (Chrome)
location /.well-known/traffic-advice {
types { } default_type "application/trafficadvice+json; charset=utf-8";
return 200 "[{\n \"user_agent\": \"prefetch-proxy\",\n \"google_prefetch_proxy_eap\": {\n \"fraction\": 1.0\n }\n}]";
allow all;
}
# Tolak akses file umum dari Git repo atau file sensitif lainnya
location ~* "/(readme|license|example|README|LEGALNOTICE|INSTALLATION|CHANGELOG)\.(txt|html|md)" {
deny all;
}
# Tolak file backup/log/extensions berbahaya
location ~* \.(old|orig|original|php#|php~|php_bak|save|swo|aspx?|tpl|sh|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rdf|gz|zip|bz2|7z|pem|asc|conf|dump)$ {
deny all;
}
# Blok pola URL mencurigakan
location ~* "/(=|\$&|_mm|(wp-)?config\.|cgi-|etc/passwd|muieblack)" {
deny all;
}
# Blok fungsi atau pola eksploitasi
location ~* "(base64_encode)(.*)(\()" { deny all; }
location ~* "(eval\()" { deny all; }
location ~* "(127\.0\.0\.1)" { deny all; }
location ~* "([a-z0-9]{2000})" { deny all; }
location ~* "(javascript\:)(.*)(\;)" { deny all; }
location ~* "(GLOBALS|REQUEST)(=|\[|%)" { deny all; }
location ~* "(<|%3C).*script.*(>|%3)" { deny all; }
location ~* "(boot\.ini|etc/passwd|self/environ)" { deny all; }
location ~* "(thumbs?(_editor|open)?|tim(thumb)?)\.php" { deny all; }
location ~* "(\'|\")(.*)(drop|insert|md5|select|union)" { deny all; }
location ~* "(https?|ftp|php):/" { deny all; }
location ~* "(=\\\'|=\\%27|/\\\'/?)\." { deny all; }
location ~* "(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")" { deny all; }
location ~ "(~|`|<|>|:|;|%|\\|\s|\{|\}|\[|\]|\|)" { deny all; }
Konfigurasi Cache (Opsional) #
Langkah ini bersifat opsional dan dapat dilewati jika Anda tidak ingin mengaktifkan cache pada Nginx.
1. Buat File Konfigurasi Cache Umum #
Buat file cache_common
yang berisi pengaturan cache dasar:
nano /etc/nginx/cache_common
Isi file dengan:
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# Optional cache bypass conditions
# fastcgi_no_cache $no_cache $http_pragma $http_authorization $arg_nocache;
# fastcgi_cache_bypass $no_cache $http_pragma $http_authorization $arg_nocache;
fastcgi_no_cache $no_cache $http_authorization;
fastcgi_cache_bypass $no_cache $http_authorization;
fastcgi_cache_valid 5m;
fastcgi_cache_use_stale http_500 http_503 updating;
fastcgi_cache_background_update on;
2. Buat File custom_cache
untuk Pengaturan Dinamis
#
File ini berisi logika tambahan untuk menentukan kapan cache harus dinonaktifkan, misalnya untuk pengguna login atau area admin:
nano /etc/nginx/custom_cache
Isi file dengan:
add_header X-Cache-Status $upstream_cache_status;
set $no_cache "";
set $cache_cookie $http_cookie;
# Nonaktifkan cache jika ada cookie
if ($cache_cookie !~ "^\s*$") {
set $no_cache 1;
}
# Nonaktifkan cache untuk CMS dan ekstensi yang umum
if ($http_cookie ~* "(joomla_[a-zA-Z0-9_]+|userID|wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordpress_logged_in_[a-zA-Z0-9]+|sid_customer_|sid_admin_|PrestaShop-[a-zA-Z0-9]+|SESS[a-zA-Z0-9]+|SSESS[a-zA-Z0-9]+|NO_CACHE|external_no_cache|adminhtml|private_content_version)") {
set $no_cache 1;
}
# Nonaktifkan cache untuk area admin CMS
if ($request_uri ~* "(/administrator|/wp-admin|/wp-login.php)") {
set $no_cache 1;
}
3. Tambahkan Konfigurasi Cache di web1.conf
#
Edit file virtualhost Anda:
nano /etc/nginx/conf.d/web1.conf
Tambahkan konfigurasi berikut (pastikan fastcgi_cache_path
berada di luar blok server {}
):
fastcgi_cache_path /var/cache/nginx/web1.example.com levels=1:2 keys_zone=web1.example.com:50m max_size=256m;
server {
listen 80;
server_name web1.example.com;
client_max_body_size 128m;
access_log /var/log/nginx/web1.access.log rt_cache;
error_log /var/log/nginx/web1.error.log;
root /home/web1/public_html;
index index.html index.cgi index.pl index.php index.xhtml index.htm index.shtml;
disable_symlinks if_not_owner from=/home/web1/public_html;
# SEO-friendly permalink fallback
set $sef_entry_point /;
if ($uri ~* "^/") {
set $sef_entry_point "/index.php?$args";
}
location @wpt_permalinks_fallback {
try_files $uri $sef_entry_point;
}
error_page 404 = @wpt_permalinks_fallback;
error_page 405 = @wpt_permalinks_fallback;
include location.conf;
include custom_cache;
location ~ \.php(/.*)?$ {
try_files $uri $fastcgi_script_name =404;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:/var/opt/remi/php74/run/php-fpm/web1.sock;
fastcgi_read_timeout 300;
fastcgi_cache web1.example.com;
include /etc/nginx/fastcgi.conf;
include /etc/nginx/cache_common;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Restart Service #
Terakhir, restart layanan PHP-FPM dan Nginx agar perubahan konfigurasi diterapkan:
systemctl restart php74-php-fpm nginx
Test akses web melalui http://web1.example.com
Optimasi #
Berikut merupakan tambahan konfigurasi untuk optimasi webserver dan php-fpm.
Langkah ini opsional dan dapat Anda lewati.
nginx.conf
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
pcre_jit on;
events {
multi_accept on;
use epoll;
worker_connections 65535;
accept_mutex on;
}
http {
## Basic Settings ##
server_tokens off;
aio threads;
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
client_body_timeout 30s; # Use 5s for high-traffic sites
client_header_timeout 30s; # Use 5s for high-traffic sites
client_max_body_size 1024m;
keepalive_requests 1024;
keepalive_timeout 30s;
send_timeout 30s;
open_file_cache max=200000 inactive=20s;
open_file_cache_errors on;
open_file_cache_min_uses 2;
open_file_cache_valid 30s;
port_in_redirect off;
reset_timedout_connection on;
sendfile on;
server_name_in_redirect off;
server_names_hash_bucket_size 1024;
server_names_hash_max_size 1024;
tcp_nodelay on;
tcp_nopush on;
types_hash_max_size 2048;
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
## Gzip Settings ##
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_disable "msie6";
gzip_min_length 1000;
gzip_proxied any;
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/wasm
application/x-font-opentype
application/x-font-truetype
application/x-font-ttf
application/x-javascript
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
application/xml+rss
font/eot
font/opentype
font/otf
image/bmp
image/svg+xml
image/vnd.microsoft.icon
image/x-icon
image/x-win-bitmap
text/cache-manifest
text/calendar
text/css
text/javascript
text/markdown
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy
text/x-js
text/xml;
gzip_vary on;
gzip_static on;
gzip_http_version 1.1;
## Security Headers ##
more_set_headers "X-XSS-Protection: 1; mode=block";
more_set_headers "X-Frame-Options: SAMEORIGIN";
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
## Log format Settings ##
log_format rt_cache '$remote_addr $upstream_response_time $upstream_cache_status [$time_local] '
'$host "$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$server_protocol" "$http3"';
## SSL Settings ##
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_prefer_server_ciphers on;
ssl_ciphers 'TLS13+AESGCM+AES256:TLS13+AESGCM+AES128:TLS13+CHACHA20:EECDH+AESGCM:EECDH+CHACHA20';
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:P-521:P-384:P-256;
# Enable 0-RTT support for TLS 1.3
proxy_set_header Early-Data $ssl_early_data;
ssl_early_data on;
# enable http/2
http2 on;
# oscp settings
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 1.1.1.1 8.8.4.4 1.0.0.1 valid=300s;
resolver_timeout 10;
# tls dynamic records patch directive
ssl_dyn_rec_enable on;
## Logging Settings ##
access_log off;
error_log /var/log/nginx/error.log;
## ngx_vts_module ##
vhost_traffic_status_zone;
dhparams2048.pem
openssl dhparam -out dhparams2048.pem 2048
conf.d/ssl.conf
ssl_dhparam /etc/nginx/dhparams2048.pem;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=15552000; preload" always;
php-fpm.conf
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
/etc/security/limits.conf
* hard nofile 500000
* soft nofile 500000
root hard nofile 500000
root soft nofile 500000
/opt/myscript/kernel.sh
echo 1 >/sys/kernel/mm/ksm/run
echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
echo never > /sys/kernel/mm/transparent_hugepage/enabled
/etc/modules-load.d/htcp.conf
tcp_htcp
HA #
Untuk memastikan skalabilitas, ketersediaan tinggi, dan performa optimal, Anda dapat mengonfigurasi dua PHP-FPM pool untuk satu virtual host. Langkah ini bersifat opsional.
Referensi: