Berikut merupakan cara untuk menginstall webserver Nginx dengan PHP-FPM dan Userdir. Sebelum memulai pastikan Anda sudah memilki 1 server Ubuntu dengan RAM minimal 1GB.
Install Apache #
apt update
apt install apache2
Selanjutnya edit /etc/apache2/mods-available/userdir.conf seperti berikut
<IfModule mod_userdir.c>
UserDir public_html
UserDir disabled root
UserDir enabled ubuntu
<Directory /home/*/public_html>
Options Indexes SymLinksIfOwnerMatch MultiViews ExecCGI Includes IncludesNOEXEC
AllowOverride AuthConfig FileInfo Indexes Limit
Require method GET POST OPTIONS
</Directory>
</IfModule>
Enable module userdir dan beberapa module lain untuk keperluan PHP
proxy proxy_fcgi rewrite userdir actions fcgid alias
Buat virtual host
nano /etc/apache2/sites-available/ubuntu.conf
Edit ubuntu.conf
<VirtualHost *:80>
ServerName example.com
ServerAdmin webmaster@localhost
DocumentRoot /home/ubuntu/public_html
<Directory /home/ubuntu/public_html>
Options Indexes FollowSymLinks
AllowOverride All
<IfVersion < 2.4>
Allow from all
</IfVersion>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
</Directory>
<FilesMatch \.(phtml|phar|php[0-9]*)$>
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php/php7.4-fpm.ubuntu.sock|fcgi://localhost"
</If>
</FilesMatch>
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
Enable site ubuntu
a2ensite ubuntu
Install PHP #
apt install php7.4 php7.4-bcmath php7.4-bz2 php7.4-cli php7.4-common php7.4-curl php7.4-enchant php7.4-fpm php7.4-imap php7.4-intl php7.4-json php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-xml php7.4-xmlrpc php7.4-zip
Buat pool fpm untuk user ubuntu
nano /etc/php/7.4/fpm/pool.d/ubuntu.conf
Edit ubuntu.conf
[ubuntu]
user = ubuntu
group = ubuntu
catch_workers_output = yes
chdir = /home/ubuntu/public_html
listen = /var/opt/remi/php74/run/php-fpm/ubuntu.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
listen.allowed_clients = 127.0.0.1
listen.backlog = 32768
request_slowlog_timeout = 5s
slowlog = /home/ubuntu/logs/php.slow.log
access.log = /home/ubuntu/logs/php.access.log
access.format = "[php-fpm:access] %R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
pm = ondemand
pm.max_children = 50
pm.max_requests = 250
pm.process_idle_timeout = 10
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.ini custom configuration directives
php_admin_value[process.priority] = -10
php_admin_flag[allow_url_fopen] = on
php_admin_flag[allow_url_include] = off
php_flag[display_errors] = off
php_flag[display_startup_errors] = off
php_value[error_reporting] = E_ALL & ~E_DEPRECATED & ~E_STRICT
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /home/ubuntu/logs/php.error.log
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
; abused php functions
; php_admin_value[disable_functions] = show_source, system, shell_exec, passthru, exec, popen, proc_open
php_admin_value[short_open_tag] = on
php_admin_value[sys_temp_dir] = "/home/ubuntu/tmp"
php_admin_value[upload_tmp_dir] = "/home/ubuntu/tmp"
php_admin_value[post_max_size] = 256M
php_admin_value[upload_max_filesize] = 128M
php_admin_value[max_input_vars] = 10000
php_admin_value[memory_limit] = 512M
php_admin_value[max_execution_time] = 300
php_admin_value[max_input_time] = 300
php_admin_value[doc_root] = "/home/ubuntu/public_html"
;php_admin_value[open_basedir] = "/home/ubuntu/:/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/ubuntu/tmp"
php_value[date.timezone] = "Asia/Jakarta"
php_value[soap.wsdl_cache_dir] = "/home/ubuntu/tmp"
; OPcache settings
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.interned_strings_buffer] = 16
; opcache.max_accelerated_files = Jumlah File + 20%
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_value[opcache.validate_timestamps] = 1
php_admin_value[opcache.revalidate_freq] = 60
; untuk environment produksi
; php_admin_value[opcache.validate_timestamps] = 0
; Environment variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /home/ubuntu/tmp
env[TMPDIR] = /home/ubuntu/tmp
env[TEMP] = /home/ubuntu/tmp
Buat folder docroot #
Login sebagai user ubuntu lalu buat folder public_html dan atur permission home user
mkdir public_html
chmod 711 /home/ubuntu/
Buat file index.php untuk test PHP
nano ~/public_html/index.php
Edit index.php
<?php phpinfo(); ?>
Restart service #
Terakhir restart service apache dan php-fpm
systemctl restart apache2 php7.4-fpm
Test akses web melalui http://example.com
Optimasi #
Berikut merupakan tambahan konfigurasi untuk optimasi webserver dan php-fpm.
Langkah ini opsional dan dapat Anda lewati.
httpd.conf
# Performance Tuning - Timeout
Timeout 300
# KeepAlive
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
UseCanonicalName Off
HostnameLookups Off
<IfModule reqtimeout_module>
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>
# MPM Configuration
<IfModule mpm_prefork_module>
StartServers 3
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 1000
</IfModule>
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 250
MaxConnectionsPerChild 10000
</IfModule>
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 250
MaxConnectionsPerChild 10000
</IfModule>
# Security Settings
ServerTokens Prod
ServerSignature Off
# Disable TRACE method
TraceEnable Off
# Security Headers
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
# Directory browsing security
<IfModule autoindex_module>
# Disable directory indexing by default
Options -Indexes
</IfModule>
# Limit request size (prevent DoS)
LimitRequestBody 10485760
# ETag settings
FileETag None
# Protect sensitive files
<FilesMatch "^\.">
Require all denied
</FilesMatch>
<FilesMatch "(\.bak|\.config|\.sql|\.fla|\.psd|\.ini|\.log|\.sh|\.inc|\.swp|\.dist)$">
Require all denied
</FilesMatch>
# Protect important directories
<DirectoryMatch "^\.|\/\.">
Require all denied
</DirectoryMatch>
# Status page for monitoring (restricted to localhost)
<IfModule status_module>
<Location "/server-status">
SetHandler server-status
Require local
</Location>
</IfModule>
# Info page for monitoring (restricted to localhost)
<IfModule info_module>
<Location "/server-info">
SetHandler server-info
Require local
</Location>
</IfModule>
# Protect .git directories
<DirectoryMatch "\.git">
Require all denied
</DirectoryMatch>
conf.d/ssl.conf
<IfModule ssl_module>
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLHonorCipherOrder On
SSLPassPhraseDialog builtin
SSLCompression Off
SSLSessionTickets Off
SSLOpenSSLConfCmd EarlyData off
<IfModule socache_shmcb_module>
SSLUseStapling On
SSLStaplingCache shmcb:/run/apache2/stapling_cache_shmcb(256000)
# Prevent browsers from failing if an OCSP server is temporarily broken.
SSLStaplingReturnResponderErrors off
SSLStaplingErrorCacheTimeout 60
SSLStaplingFakeTryLater off
SSLStaplingResponderTimeout 5
SSLSessionCache shmcb:/run/apache2/ssl_gcache_data_shmcb(1024000)
</IfModule>
<IfModule !socache_shmcb_module>
SSLSessionCache dbm:/run/apache2/ssl_gcache_data_dbm
</IfModule>
SSLSessionCacheTimeout 300
Mutex file:/run/apache2 ssl-cache
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
</IfModule>
conf.d/deflate.conf
<IfModule mod_deflate.c>
# Compression Level
DeflateCompressionLevel 5
# Teks dan data
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE application/manifest+json
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
</IfModule>
conf.d/deflate.conf
<IfModule mod_expires.c>
ExpiresActive On
# Images
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
# Video
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/mpeg "access plus 1 year"
# CSS, JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Fonts
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
ExpiresByType font/eot "access plus 1 year"
ExpiresByType font/opentype "access plus 1 year"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
# Others
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
</IfModule>
conf.d/deflate.conf
<IfModule mod_headers.c>
# Set cache control for static assets
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|svg|js|css|swf|woff|woff2|ttf|eot)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
# Set cache control for HTML
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, public"
</FilesMatch>
# Disable caching for dynamic content
<FilesMatch "\.(php|cgi|pl)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</FilesMatch>
</IfModule>
conf.d/security.conf
# Disallow remote access to .htaccess, .htpasswd, .user.ini, and php.ini files
<Files ~ "^\.ht">
Require all denied
Satisfy All
</Files>
<FilesMatch "^(\.user\.ini|php\.ini)$">
Require all denied
Satisfy All
</FilesMatch>
conf.d/error-document.conf
<Location ~ "(\.jpeg|\.jpg|\.gif|\.png|\.ico|\.js|\.css|\.map|\.json|\.xml|robots\.txt)$">
ErrorDocument 400 "400 Bad Request"
ErrorDocument 401 "401 Unauthorized"
ErrorDocument 403 "403 Forbidden"
ErrorDocument 404 "404 Not Found"
ErrorDocument 405 "405 Method Not Allowed"
ErrorDocument 500 "500 Internal Server Error"
ErrorDocument 501 "501 Not Implemented"
ErrorDocument 502 "502 Bad Gateway"
ErrorDocument 503 "503 Service Unavailable"
</Location>
php-fpm.conf
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
/etc/security/limits.conf
* soft core 0
* hard core 0
* soft data unlimited
* hard data unlimited
* soft nice 0
* hard nice 0
* soft fsize unlimited
* hard fsize unlimited
* soft sigpending 62793
* hard sigpending 62793
* soft memlock 64
* hard memlock 64
* soft rss unlimited
* hard rss unlimited
* soft nofile 500000
* hard nofile 500000
* soft msgqueue 819200
* hard msgqueue 819200
* soft rtprio 0
* hard rtprio 0
* soft stack 10240
* hard stack 10240
* soft cpu unlimited
* hard cpu unlimited
* soft nproc unlimited
* hard nproc unlimited
* soft as unlimited
* hard as unlimited
* soft locks unlimited
* hard locks unlimited
root hard nofile 500000
root soft nofile 500000
root soft nproc unlimited
root hard nproc unlimited
/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