SSD Nodes Learn Hosting plans →
Mga Gabay Matt ConnorNi Matt Connor

Apache vs Nginx: Alin ang Dapat Patakbuhin ng VPS Mo?

Lilipat ka ba ng PHP site mula shared hosting papunta sa VPS? Alamin kung bakit hindi gagana ang .htaccess mo sa Nginx at kailan mas sulit manatili sa Apache.

Apache vs Nginx: ang maikling sagot

Sa Apache vs Nginx, ang tamang pili para sa unang VPS (virtual private server) mo ay nakasalalay sa isang tanong: umaasa ba ang PHP site mo sa .htaccess? Kung oo at ayaw mo munang galawin ang config, manatili sa Apache. Kung handa kang ilipat ang mga rule sa server config, magaan at diretso ang Nginx, lalo na kung kasama ang PHP-FPM.

Pareho silang sapat na mabilis para sa karaniwang WordPress o Laravel site. Mas malaki ang epekto ng PHP at ng database kaysa sa web server mismo. Kaya nakatuon ang gabay na ito sa mga bagay na talagang nasisira kapag lumipat ka, at sa paraan ng pagsukat sa sarili mong server. Hindi ito install tutorial. Para sa pag-install, nandiyan ang gabay sa pag-set up ng LAMP stack sa Ubuntu 24.04.

Saan nanggaling ang site mo?

Karamihan ng lumilipat sa VPS ay galing sa isa sa dalawang lugar. Ang una ay shared hosting na may cPanel. Ang pangalawa ay XAMPP sa sariling laptop, halimbawa isang capstone project o maliit na sistema ng negosyo ng pamilya na kailangan nang i-online.

Sa parehong kaso, may .htaccess na tahimik na gumagana. May kasamang Apache ang XAMPP, kaya binabasa nito ang .htaccess. Maraming shared host naman ang gumagamit ng LiteSpeed Web Server, hindi Apache. Sinusunod din ng LiteSpeed ang .htaccess rules, kaya gumana ang mga rule mo kahit hindi mo alam kung anong server ang nasa likod. Dahil dito, maaaring hindi mo pa napapansin na umaasa ang site mo sa file na iyon. Mapapansin mo lang ito sa unang araw sa Nginx, kapag 404 na ang lahat ng pahina maliban sa homepage.

Kung hindi mo pa nailipat ang mga file at database, basahin muna ang paglipat mula shared hosting papunta sa VPS. Pagkatapos, bumalik dito para piliin ang web server.

Ano ang tunay na pagkakaiba ng Apache at Nginx?

Nasa paraan ng paghawak ng bawat koneksyon ang pagkakaiba. Doon nanggagaling ang lahat ng iba pang pagkakaiba sa memory at sa config.

Apache at ang mga MPM nito

Gumagamit ang Apache ng MPM (multi-processing module) para magpasya kung paano hahatiin ang trabaho. Isa lang ang aktibong MPM sa isang pagkakataon.

  • prefork: isang buong process bawat koneksyon, walang threads. Ito ang kailangan ng mod_php, dahil hindi lahat ng PHP extension ay ligtas gamitin sa threads.
  • worker: ilang process, at bawat isa ay may maraming thread. Isang thread bawat koneksyon.
  • event: katulad ng worker, pero may hiwalay na listener thread para sa mga koneksyong naka-keep-alive at walang ginagawa. Kaya hindi nakatali ang isang worker thread sa browser na naghihintay lang.

Sa prefork na may mod_php, may sariling kopya ng PHP interpreter ang bawat Apache process. Kahit para lang sa isang larawan o CSS file ang request, process na may dalang PHP ang humahawak nito. Dito galing ang reputasyon ng Apache na mabigat sa RAM. Ang totoong sanhi ay ang kombinasyon ng prefork at mod_php, hindi ang Apache mismo.

Nginx at ang event loop

May isang master process ang Nginx at ilang worker process, kadalasan isa bawat CPU core. May event loop ang bawat worker: binabantayan nito ang maraming koneksyon nang sabay at kumikilos lang kapag may dumating na data. Walang bagong process o thread para sa bawat bisita. Kaya maliit at halos hindi gumagalaw ang memory ng Nginx kahit dumami ang koneksyon.

Hindi nagpapatakbo ng PHP ang Nginx. Ipinapasa nito ang bawat .php request sa PHP-FPM (FastCGI Process Manager), isang hiwalay na serbisyo na may sariling pool ng PHP worker.

Ano ang ibig sabihin nito sa VPS na may 1 o 2 GB na RAM?

Sa isang PHP site, sa mga PHP worker napupunta ang malaking bahagi ng memory, hindi sa web server. Ang isang PHP worker na nagpapatakbo ng WordPress na maraming plugin ay maaaring gumamit ng sampu-sampung megabyte. Mas maliit nang malayo ang Nginx worker o ang Apache event process na naghahatid lang ng static file.

Ganito ang praktikal na bunga. Sa Apache prefork na may mod_php, ang bilang ng sabay-sabay na koneksyon ay katumbas ng bilang ng PHP interpreter sa memory. Ang MaxRequestWorkers na masyadong mataas sa 1 GB na VPS ay nauuwi sa swap, o sa OOM killer (out-of-memory killer) ng kernel na pumapatay ng process para mabawi ang RAM. Sa PHP-FPM naman, sa Apache man o sa Nginx, ang bilang ng PHP worker ay itinatakda ng pm.max_children sa pool config. Hiwalay ito sa bilang ng koneksyon. Naghahatid ang web server ng static files at naghihintay sa mabagal na browser nang hindi kumakain ng PHP memory.

Kaya kapag PHP-FPM na ang gamit ng parehong server, maliit na lang ang agwat ng Apache event at Nginx sa memory. Ang mas mahalagang setting ay ang laki ng PHP-FPM pool, at may hiwalay na gabay para diyan: pagtatakda ng tamang laki ng PHP-FPM pool sa maliit na VPS.

Paano sukatin ito sa sarili mong server?

Huwag umasa sa benchmark ng iba. Iba ang plugins mo, iba ang tema, at iba ang CPU ng VPS mo. Apat na sagot ang kailangan mo mula sa sarili mong makina.

Una, alamin kung anong MPM at PHP module ang aktibo sa Apache:

sudo apachectl -V | grep -i mpm
sudo apachectl -M | grep -Ei 'mpm|php|proxy_fcgi'

Kung may lumabas na php_module, mod_php ang gamit mo at halos tiyak na prefork ang MPM. Kung proxy_fcgi_module ang nakikita at walang php_module, PHP-FPM na ang humahawak ng PHP.

Pangalawa, tingnan ang kabuuang memory ng bawat grupo ng process:

free -m
ps -C apache2 -o rss= | awk '{s+=$1} END {print s/1024 " MB apache2"}'
ps -C nginx -o rss= | awk '{s+=$1} END {print s/1024 " MB nginx"}'
ps -eo rss,comm | awk '/php-fpm/ {s+=$1} END {print s/1024 " MB php-fpm"}'

Ang RSS (resident set size) ay ang RAM na hawak ng isang process. Medyo sobra ang kabuuan dahil paulit-ulit na nabibilang ang shared memory. Sapat pa rin ito para ikumpara ang dalawang setup sa iisang makina.

Pangatlo, magpadala ng load habang binabantayan mo ang memory sa ibang terminal. Nasa package na apache2-utils ang ab (ApacheBench):

sudo apt install -y apache2-utils
ab -n 2000 -c 50 http://127.0.0.1/

Patakbuhin ito sa VPS mismo, hindi mula sa laptop mo, para hindi ang internet connection mo ang masukat. Ikumpara ang Requests per second at Failed requests ng dalawang setup. Pang-apat, ulitin ang test sa isang mabigat na pahina, halimbawa ang search page o ang listahan ng produkto. Doon talaga nagtatrabaho ang PHP at ang database.

Bakit hindi gumagana ang .htaccess sa Nginx?

Dahil walang ganitong mekanismo ang Nginx. Binabasa ng Apache ang .htaccess sa bawat directory, sa bawat request, kapag pinapayagan ito ng AllowOverride sa config. Hinahanap nito ang file sa bawat folder mula sa document root hanggang sa folder ng hinihinging file. Kaya kapag binago mo ang .htaccess, epektibo agad ito nang walang restart.

Binabasa lang ng Nginx ang config nito kapag nag-start o nag-reload. Walang per-directory file. Ordinaryong file lang para sa Nginx ang .htaccess sa folder mo. Hindi nito binabasa ang laman, at walang lumalabas na error o babala. Dapat nasa server block ang lahat ng rule.

May dahilan ang disenyong ito. Ang paghahanap ng .htaccess sa bawat directory ay dagdag na file lookup sa bawat request. Kaya kahit sa Apache, ang payo ng sarili nitong documentation ay ilagay ang mga rule sa main config at itakda ang AllowOverride None kapag may access ka sa server config. Sa VPS, may access ka na.

Paano ilipat ang WordPress rewrite rules sa Nginx?

Ito ang default na .htaccess ng WordPress para sa pretty permalinks, bilang halimbawang config excerpt:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Ganito ang sinasabi nito: kung hindi totoong file (!-f) at hindi totoong directory (!-d) ang hinihingi, ipasa ang request sa /index.php. Ang WordPress na ang bahala sa URL.

Sa Nginx, isang linya ang katumbas nito, ang try_files. Narito ang isang halimbawang server block:

server {
    listen 80;
    server_name example.com www.example.com;
    root /srv/example.com/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

Sumusubok ang try_files ayon sa pagkakasunod-sunod: ang file mismo ($uri), tapos ang directory ($uri/), tapos ang /index.php kasama ang query string. Pareho ito ng lohika ng !-f at !-d. Palitan ang fastcgi_pass ng tunay na pangalan ng socket sa server mo. Makikita ito sa ls /run/php/.

Hinaharang ng huling location ang pag-download ng mga .htaccess at .htpasswd na naiwan sa folder. Mahalaga ito dahil wala nang Apache na nagbabantay sa mga file na iyon. Kung may password hash sa .htpasswd, makukuha ito ng sinumang humiling nito.

Bago mag-reload, laging subukan muna ang syntax:

sudo nginx -t
sudo systemctl reload nginx

Kapag may mali, ipinapakita ng nginx -t ang file at ang line number. Huwag mag-reload hangga't hindi ito pumapasa. Hindi pinuputol ng reload ang mga kasalukuyang koneksyon.

Ang katumbas para sa Laravel

Nasa public/ folder ang .htaccess ng Laravel at pareho ang lohika nito. Ito ang katumbas sa Nginx:

root /srv/myapp/public;

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Ituro ang root sa public/, hindi sa ugat ng project. Kapag mali ito, maaaring ma-download ng bisita ang .env file na may password ng database mo.

Paano ilipat ang access control mula .htaccess?

Mas delikado ito kaysa rewrite rules. Kapag mali ang rewrite, makikita mo agad ang 404. Kapag nawala ang access control, gumagana pa rin ang site. Bukas na lang ang mga file na dati ay sarado.

Karaniwang halimbawa ang .htaccess sa wp-content/uploads/ na pumipigil sa pagpapatakbo ng PHP doon. Sa Apache 2.4, ganito ang hitsura ng rule:

<Files "*.php">
    Require all denied
</Files>

Hindi na ito binabasa ng Nginx. Kung may mag-upload ng PHP file sa uploads folder gamit ang butas sa isang plugin, ipapasa ito ng location ~ \.php$ sa PHP-FPM at tatakbo ito. Ilipat ang rule sa server block at ilagay ito bago ang location ~ \.php$. Sinusuri ng Nginx ang mga regex location ayon sa pagkakasulat, at ang unang tumugma ang ginagamit:

location ~* ^/wp-content/uploads/.*\.php$ {
    deny all;
}

Bago mo patayin ang Apache, hanapin ang lahat ng .htaccess sa site mo at basahin ang bawat isa:

find /srv/example.com/public -name .htaccess -print

Gumawa ng listahan. Dapat may katumbas sa Nginx config ang bawat linya, o may malinaw na dahilan kung bakit hindi na ito kailangan. Kasama rito ang Deny from all o Require all denied, ang AuthType Basic (na nagiging auth_basic at auth_basic_user_file sa Nginx), ang mga Redirect 301, at ang mga Header set para sa cache. Madalas magsulat ng sariling block sa .htaccess ang mga cache plugin at security plugin ng WordPress. Kaya basahin ang buong file, hindi lang ang WordPress block.

mod_php o PHP-FPM: paano tatakbo ang PHP?

May dalawang paraan ang Apache para magpatakbo ng PHP. Inilalagay ng mod_php ang PHP sa loob mismo ng Apache process. Simple ito, at ito ang dahilan kung bakit gumagana agad ang PHP sa XAMPP. Pero kailangan nito ng prefork, kaya may dalang PHP interpreter ang bawat koneksyon.

Ang pangalawang paraan ay PHP-FPM sa pamamagitan ng mod_proxy_fcgi. Dito, maaaring tumakbo ang Apache sa event MPM, at nasa sariling pool ang PHP. Ito rin ang paraan ng Nginx, dahil PHP-FPM lang ang opsyon nito. Kaya makukuha mo ang pangunahing benepisyo sa memory nang hindi umaalis sa Apache: lumipat sa event at PHP-FPM, at gagana pa rin ang .htaccess mo. Isa pang bentahe: maaaring may sariling pool ang bawat site na tumatakbo bilang ibang Linux user, kaya hindi mababasa ng isang na-hack na site ang mga file ng iba.

May isang bagay na masisira sa paglipat na ito. Mga directive ng mod_php ang php_value at php_flag sa .htaccess. Kapag wala na ang module, hindi na kilala ng Apache ang mga ito at 500 Internal Server Error ang ibinabalik nito. Ilipat ang mga setting na iyon sa .user.ini sa document root, o sa php_admin_value sa pool config.

Kailan may saysay ang Nginx sa harap ng Apache?

Kilalang setup ito: nakikinig ang Nginx sa port 80 at 443, hinahawakan ang TLS (transport layer security) at ang static files, at ipinapasa ang iba sa Apache na nakikinig lang sa 127.0.0.1:8080. Nananatili ang .htaccess dahil Apache pa rin ang nagpoproseso ng PHP request.

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Sa panig ng Apache, palitan ang Listen 80 sa ports.conf ng Listen 127.0.0.1:8080, at buksan ang mod_remoteip para makita ang tunay na IP ng bisita:

sudo a2enmod remoteip

Pagkatapos, idagdag sa Apache config ang RemoteIPHeader X-Forwarded-For at RemoteIPInternalProxy 127.0.0.1, at i-restart ang Apache. Kung wala ito, 127.0.0.1 ang lahat ng bisita sa access log. Dahil dito, hindi na gumagana nang tama ang mga rule na humaharang batay sa IP.

Para sa maliit na VPS, kadalasan ay hindi sulit ang dalawang web server. Dalawang config ang babantayan at dalawang log ang babasahin kapag may problema. Kadalasan ay sapat na ang Apache na may event at PHP-FPM. Gamitin ang setup na ito kapag may tiyak kang dahilan, halimbawa kapag may ilang app sa iisang server at hindi PHP ang ilan sa mga ito. Para sa detalye ng bawat proxy_set_header, basahin ang paliwanag ng Nginx reverse proxy config, linya por linya. Kung reverse proxy mismo ang pinipili mo, ang paghahambing ng Nginx, Caddy at Traefik bilang reverse proxy ang tamang basahin.

Alin ang pipiliin: Apache o Nginx?

Manatili sa Apache kapag:

  • Maraming .htaccess ang site mo at hindi mo pa nababasa ang lahat ng ito.
  • Gumagamit ka ng plugin na sumusulat sa .htaccess at umaasang epektibo ito agad, gaya ng ilang cache at security plugin ng WordPress.
  • Ibang tao ang nag-a-upload ng mga site at hindi nila hawak ang server config, halimbawa mga kliyente mo.
  • Gusto mong makalipat agad ngayon at ayusin ang performance pagkatapos. Lumipat lang sa event at PHP-FPM.

Piliin ang Nginx kapag:

  • Bago ang site o kaunti lang ang .htaccess rules, at kaya mong ilipat ang lahat sa isang server block.
  • Maraming static file o maraming mabagal na koneksyon ang site mo, at gusto mo ng maliit at matatag na memory ng web server.
  • Gagamitin mo rin ang server bilang reverse proxy para sa ibang app, gaya ng Node.js o Python.
  • Gusto mong nasa iisang lugar ang lahat ng rule, naka-commit sa git, at sinusuri ng nginx -t bago mag-reload.

Pagkatapos pumili, HTTPS ang susunod na hakbang. May hiwalay na gabay para sa bawat isa: Certbot at Let's Encrypt para sa Apache at Certbot at Let's Encrypt para sa Nginx.

FAQ

Bakit 404 ang lahat ng pahina ng WordPress ko pagkalipat sa Nginx?

Dahil hindi binabasa ng Nginx ang .htaccess, kaya walang rule na nagpapasa ng mga permalink sa index.php. Gumagana lang ang homepage dahil totoong file ito. Idagdag ang try_files $uri $uri/ /index.php?$args; sa location / ng server block, patakbuhin ang sudo nginx -t, at saka i-reload ang Nginx.

Mas mabilis ba talaga ang Nginx kaysa Apache para sa PHP site?

Para sa static files at maraming sabay-sabay na koneksyon, mas magaan ang Nginx. Para sa mga PHP page, ang PHP-FPM at ang database ang kadalasang kumukuha ng karamihan ng oras, at magagamit ng parehong server ang PHP-FPM. Ang malaking agwat sa memory ay kadalasang galing sa Apache prefork na may mod_php. Sukatin ito sa sarili mong VPS gamit ang ab at ps bago magpasya.

Gumana ang .htaccess ko sa shared hosting. Apache ba ang gamit ng host ko?

Hindi kinakailangan. Maraming shared host ang gumagamit ng LiteSpeed Web Server, na sumusunod din sa .htaccess rules. Kaya umaasa sa .htaccess ang site na gumana roon kahit hindi Apache ang server. Kapag lilipat ka sa Nginx, ituring na kailangang ilipat ang bawat linya ng file na iyon sa server block.

Bakit 500 Internal Server Error ang Apache pagkatapos kong lumipat sa PHP-FPM?

Kadalasan ay dahil sa mga php_value o php_flag na linya sa .htaccess. Mga directive ito ng mod_php, kaya kapag naka-disable na ang module, hindi na kilala ng Apache ang mga ito. Sa error log ng Apache, makikita mo ang Invalid command 'php_value'. Ilipat ang mga setting sa .user.ini sa document root o sa php_admin_value sa PHP-FPM pool config.