Ano ang HTTP? Gabay para sa server admin
Alamin ang HTTP para sa server admin: methods, status codes, mahahalagang headers, nginx logs, at kung saan pumapasok ang HTTP/3 at TLS.
Ano ang HTTP?
Ang HTTP (hypertext transfer protocol) ay set ng mga panuntunan na ginagamit ng client at web server para humiling ng isang bagay at ibalik ito. Nagpapadala ang client ng request: isang method gaya ng GET, isang path gaya ng /pricing, protocol version, listahan ng mga header, at kung minsan ay body. Sumasagot ang server gamit ang status code gaya ng 200, na sinusundan ng sarili nitong mga header at karaniwang body. Ang bawat page view at bawat API (application programming interface) call sa iyong server ay ganoong exchange na paulit-ulit na isinasagawa.
Walang sariling state ang HTTP. Hindi naaalala ng server kung ano ang hiniling mo isang segundo ang nakalipas, kaya ang anumang gumaganang parang memory, gaya ng login session, ay inilalagay sa isang header sa bawat request. Malaking bahagi ng mga susunod na paliwanag ay nagmumula sa property na ito: header-driven nang buo ang caching, at maaaring ipadala ng load balancer ang susunod mong request sa ibang backend nang walang anumang problema.
Ipinapakita sa ibaba kung ano ang hitsura ng modelong ito mula sa panig ng server, sa iyong access log at sa iyong nginx config.
Isang raw request at response, may mga annotation
Narito ang isang kumpletong HTTP/1.1 request. Tinatapos ng blank line ang mga header, at ang anumang kasunod ng linyang iyon ang body. Karaniwan, walang body ang isang GET.
GET /pricing HTTP/1.1
Host: example.com
User-Agent: curl/8.5.0
Accept: */*
Accept-Encoding: gzip- Ang
GETang method na nagsasaad ng aksiyong gusto mong gawin. Binabasa ngGET, nagpapadala ng data angPOST, pinapalitan ngPUT, inaalis ngDELETE, at hinihingi ngHEADang mga header ng isangGETnang walang body. - Ang
/pricingang path. Hindi bahagi ng request line ang hostname, kaya may kasunod na header para rito. - Ang
HTTP/1.1ang protocol version na ginagamit ng client. - Tinutukoy ng
Host: example.comang site na gusto ng client. Kinakailangan ito ng HTTP/1.1, kaya sinasagot ng nginx ng400 Bad Requestang request na wala nito. - Ang iba pa ay mga preference. Sinasabi ng
Accept-Encoding: gzipna kayang mag-decompress ng client, kaya maaaring i-compress ng server ang body.
Pareho ang anyo ng response, pero may status line sa itaas.
HTTP/1.1 200 OK
Date: Thu, 06 Aug 2026 09:12:44 GMT
Server: nginx
Content-Type: text/html; charset=utf-8
Content-Length: 5310
Cache-Control: public, max-age=300
<!doctype html>...- Ang
200 OKang status code kasama ang reason phrase nito. Ang code ang mahalaga. Pangdekorasyon lamang ang phrase at binabalewala ito ng mga client. - Sinasabi ng
Content-Typesa client kung paano ituring ang mga byte na kasunod nito. - Ang
Content-Lengthang laki ng body sa bytes, kaya alam ng client kung saan nagtatapos ang body. Kapag hindi pa alam ang laki, sa halip ay ipinapadala ng server angTransfer-Encoding: chunkedat minamarkahan ang dulo gamit ang chunk na may zero length. - Sinasabi ng
Cache-Controlsa browser at sa anumang cache sa pagitan kung gaano katagal nila maaaring itago ang response na ito. - Ang blank line pagkatapos ng mga header ang naghihiwalay sa mga ito mula sa body, sa parehong direksiyon.
Case insensitive ang mga pangalan ng header, at nagtatapos ang bawat linya sa carriage return na sinusundan ng line feed, sa halip na isang newline lamang. Hindi mo ito manu-manong ita-type, pero makikita mo ang mga ito sa isang packet capture.
Para subaybayan ang isang aktuwal na pares, patakbuhin ito laban sa site na pagmamay-ari mo:
curl -sS -o /dev/null -D - https://example.com/Isinusulat ng -D - ang mga response header sa iyong terminal, at itinatapon ng -o /dev/null ang body. Mas mainam ito kaysa sa curl -I dahil nagpapadala ang -I ng HEAD request. Ang application server na iba ang paghawak sa HEAD kaysa sa GET, gaya ng ginagawa ng marami, ay magpapakita sa iyo ng mga header na hindi kailanman natatanggap ng browser. Ipinapakita ng curl -v ang magkabilang panig, kung saan minamarkahan ang mga request line bilang > at ang mga response line bilang <.
Kung ano ang hitsura ng request line sa nginx access log
May kasamang combined log format ang nginx, at ito ang definition nito:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';Isang line na ginawa nito:
203.0.113.45 - - [06/Aug/2026:09:12:44 +0000] "GET /pricing HTTP/1.1" 200 5310 "https://example.com/" "Mozilla/5.0 (X11; Linux x86_64) Chrome/127.0.0.0 Safari/537.36"- Ang
203.0.113.45ay$remote_addr, ang address na nagbukas ng TCP (transmission control protocol) connection. Kapag nasa likod ng proxy, proxy ang address na ito, hindi ang visitor. - Ang unang
-ay fixed placeholder. Ang pangalawa ay$remote_user, na napupunan lamang kapag gumagamit ng HTTP basic authentication. - Ang
"GET /pricing HTTP/1.1"ay$request, ang request line na eksaktong kinopya kung paano ito dumating. - Ang
200ay ang status na ibinalik ng iyong server, hindi ang status na nakita ng visitor. - Ang
5310ay$body_bytes_sent, ang body lamang. Hindi kasama ang response headers, kaya palaging mas maliit ang numerong ito kaysa sa aktuwal na bytes na naipadala. - Ang huling dalawang naka-quote na field ay
RefereratUser-Agent. Pareho itong galing sa client, kaya maaaring maglaman ng kahit ano.
Dahil verbatim na kinokopya ang $request, verbatim ding lumalabas ang junk. Ang client na gumagamit ng TLS (transport layer security) sa plaintext port 80 ay nag-iiwan ng 400 line na ang request field ay nagsisimula sa mga escaped byte gaya ng "\x16\x03\x01\x02\x00\x01". Ang \x16 ay ang TLS handshake record type, kaya ang mga byte na iyon ay simula ng ClientHello at hindi request line. Tama ang pagkilos ng iyong server. May nagtuturo ng HTTPS sa HTTP port.
Idagdag din ang $server_protocol sa iyong log format. Ipi-print nito ang HTTP/1.1, HTTP/2.0, o HTTP/3.0, at ito ang pinakamabilis na paraan upang mapatunayan na aktuwal na nagkabisa ang pagbabago ng protocol.
Ano ang ibig sabihin ng mga karaniwang status code kapag ibinabalik ang mga ito ng sarili mong site
Ang unang digit ang nagsasabi ng class, at ang class ang dapat mong basahin muna.
Ibig sabihin ng 2xx ay matagumpay ang request. 200 OK para sa karaniwang pagbasa. 201 Created pagkatapos ng POST na lumikha ng isang resource. 204 No Content para sa matagumpay na request na walang kailangang ibalik, na karaniwang sagot sa DELETE.
Ibig sabihin ng 3xx ay sa ibang lokasyon dapat tumingin. Permanent ang 301 at agresibong ini-cache ito ng mga browser, kung minsan hanggang i-clear ng user ang profile niya, kaya mahirap bawiin ang 301 na tumuturo sa maling hostname. Gamitin ang 302 habang tine-test mo pa ang redirect. Ang 304 Not Modified ay tagumpay, hindi error: nagpadala ang client ng If-None-Match na may ETag (entity tag) na kinikilala mo pa, kaya headers lang at walang body ang ibinalik mo. Kapag puno ng mga 304 ang log, gumagana ang caching.
Ibig sabihin ng 4xx ay mali ang request. Maling input ang 400 Bad Request. Ang 401 Unauthorized ay talagang nangangahulugang hindi authenticated, at dapat itong may WWW-Authenticate header na nagsasaad ng scheme. Ang 403 Forbidden ay nangangahulugang naunawaan ang request pero tinanggihan pa rin. Ang 404 Not Found ay path na hindi umiiral. Ang 405 Method Not Allowed ay tamang path pero maling method, na ibinabalik ng POST sa isang static file location. Ang 413 ay body na mas malaki sa client_max_body_size ng nginx, na naka-default sa 1 megabyte, at kinukumpirma ito ng error log gamit ang client intended to send too large body.
Ang 403 sa isang static file ay halos palaging problema sa filesystem, hindi sa HTTP rule. Basahin ang /var/log/nginx/error.log bago magbago ng configuration. Ang open() "/srv/site/index.html" failed (13: Permission denied) ay nangangahulugang hindi mabasa ng nginx worker user ang file, kadalasan dahil walang execute permission para sa ibang user ang parent directory. Ang directory index of "/srv/site/" is forbidden ay nangangahulugang nag-resolve ang path sa isang directory na walang index file habang naka-off ang autoindex.
Ibig sabihin ng 5xx ay may nasira sa panig mo. Ang 500 ay hindi nahawakang error sa application mo. Ang 502 Bad Gateway ay nangangahulugang hindi nakakuha ang nginx ng magagamit na response mula sa upstream, at tinutukoy ng error log ang sanhi: ang connect() failed (111: Connection refused) while connecting to upstream ay nangangahulugang walang nakikinig sa address sa proxy_pass. Ang 504 Gateway Timeout ay nangangahulugang tinanggap ng upstream ang connection pero walang ipinadala sa loob ng proxy_read_timeout, na naka-default sa 60 seconds; itinatala ito ng log bilang upstream timed out (110: Connection timed out) while reading response header from upstream. Ang 503 Service Unavailable ay sinadyang pagtanggi. Tandaan na 503 ang ibinabalik ng sariling rate limiter ng nginx, dahil naka-default ang limit_req_status sa 503. Kung hinahanap mo ang 429 Too Many Requests sa log pero 503 ang nakikita mo, iyon ang dahilan. Itakda ang limit_req_status 429; para makuha ang tamang code.
Mahalagang headers kapag pinapatakbo ang server
Host ang pumipili sa site. Maaaring maghatid ang isang IP address ng daan-daang hostname, at itinutugma ng nginx ang Host sa server_name upang matukoy kung aling server block ang sasagot. Kung walang tumugma, ginagamit ng nginx ang default server. Ito ang unang block na nakikinig sa address at port na iyon, maliban kung may ibang minarkahan bilang default_server. Kung maling site ang ibinalik mula sa bagong virtual host, halos palaging ito ang dahilan: hindi tumugma ang pangalan, kaya napunta ang request sa default. Subukan ito nang hindi ginagalaw ang DNS:
curl -sS -o /dev/null -D - -H 'Host: app.example.com' http://127.0.0.1/Ang User-Agent ay self-description na isinulat ng client, at free text ito. Gamitin lamang ito bilang pahiwatig kapag nagbabasa ng logs. Huwag itong gamitin bilang control, dahil madaling magsinungaling ang client tungkol dito. Kaya kapag bina-block ang scraper gamit ang User-Agent, ang mga scraper na sumusunod lamang sa patakaran ang karaniwang nahaharangan.
Ang Content-Type ang nagtatakda kung paano bibigyang-kahulugan ang mga byte: application/json para sa API request at text/html; charset=utf-8 para sa page. Itinutugma ng nginx ang mga file extension sa mga type gamit ang /etc/nginx/mime.types, at itinatakda ng naka-package na nginx.conf ang default_type application/octet-stream;. Dahil dito, ang file na may extension na hindi kilala ng nginx ay inihahain bilang download sa halip na i-render. Ang nakikitang sintomas ay page na naglo-load nang walang styling habang ipinapakita ng browser console ang Refused to apply style from ... because its MIME type ('text/plain') is not a supported stylesheet MIME type. Ang MIME ay nangangahulugang multipurpose internet mail extensions, ang naming scheme na pinagmulan ng mga type string na iyon.
Ang Cache-Control ang ginagamit upang kontrolin ang bawat cache sa pagitan ng server at reader. Ang public, max-age=31536000, immutable ay angkop sa mga asset na may content hash sa filename, dahil nagbabago ang pangalan kapag nagbago ang content. Ang no-store ay para sa anumang user-specific, dahil maaaring ibigay ng shared cache ang naka-login na page sa susunod na humiling ng parehong URL. Ang private ang gitnang setting: maaaring itago ito ng browser, ngunit hindi ng shared cache.
Ginagamit ang X-Forwarded-For dahil itinatago ng proxy ang visitor. Kapag dumaan na ang request sa reverse proxy, ang $remote_addr ay address ng proxy. Dahil dito, iisang client lamang ang nakikita ng logs, geolocation, at rate limiting mo. Kailangang ipasa ng proxy ang orihinal na address:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;Kailangan ding sabihin sa tumatanggap na server na pagkatiwalaan ito, at tukuyin kung sino lamang ang pagkakatiwalaan:
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;Maglista lamang ng mga range na kontrolado mo. Ang X-Forwarded-For ay plain text na maaaring ipadala ng anumang client, kaya hinahayaan ng set_real_ip_from 0.0.0.0/0; ang visitor na piliin ang address na ila-log mo at ang address na bibilangin ng rate limiter mo.
Pinipigilan ng X-Forwarded-Proto ang isang partikular at karaniwang failure. Tinatapos ng proxy ang TLS at ipinapasa ang request sa application gamit ang plain HTTP. Plain request ang nakikita ng application, kaya nagpapasya itong dapat gumamit ang visitor ng HTTPS at sumasagot ng 301 https://example.com/. Sinusundan ito ng browser, muling tinatapos ng proxy ang TLS, at ipinapasa nitong muli ang plain HTTP. Nauulit ang loop hanggang sumuko ang browser at magpakita ng ERR_TOO_MANY_REDIRECTS. Sa pagpapadala ng X-Forwarded-Proto: https, sinasabi sa application na HTTPS na ang ginagamit ng visitor, kaya hihinto ito sa pagre-redirect.
HTTP/1.1 kumpara sa HTTP/2 kumpara sa HTTP/3: ano ang magbabago para sa iyo
Text-based ang HTTP/1.1, at isang request lang ang pinoproseso nito bawat connection. Connection: keep-alive ay nagbibigay-daan sa susunod na request na gamitin muli ang parehong TCP connection, kaya nababawasan ang setup cost, pero bumabalik pa rin ang mga response ayon sa pagkakasunod ng mga request. Hinaharangan ng isang mabagal na response ang lahat ng naka-queue sa likod nito. Ito ang head-of-line blocking, at nilulutas ito ng mga browser sa pamamagitan ng pagbubukas ng ilang connection sa parehong hostname nang sabay-sabay.
Pareho pa rin ang mga method at status code sa HTTP/2, pero binary na ang framing. Maraming request ang nagshe-share ng isang connection bilang magkakahiwalay na stream, at kino-compress ang paulit-ulit na header text. Mahalaga ito dahil maraming header ang dala ng modern request. TCP pa rin ang connection, kaya kapag may nawawalang packet, natitigil ang bawat stream sa connection na iyon hanggang dumating ang retransmission. Hindi nawala ang head-of-line blocking. Bumaba lamang ito mula sa HTTP papunta sa transport layer. Bahagi ng HTTP/2 ang server push, pero hindi na ito ginagamit sa praktika dahil inalis ng Chrome ang support para rito noong 2022.
Pareho pa rin ang semantics sa HTTP/3, pero pinapalitan nito ang TCP ng QUIC, isang transport na nakabatay sa UDP (user datagram protocol). Independent ang mga QUIC stream hanggang sa pinakamababang layer, kaya ang nawawalang packet ay nakakapagpatigil lamang sa stream na kinabibilangan nito. Built in sa QUIC handshake ang TLS 1.3 sa halip na naka-layer sa ibabaw nito, kaya mas kaunti ang round trip na kailangan ng bagong connection. Dalawa ang praktikal na epekto nito: kailangang bukas ang UDP port 443 sa bawat firewall na dinaraanan ng traffic, at ibabalik ng network na naglilimita o nagba-block ng UDP ang mga client sa HTTP/2.
Ano ang konkretong magbabago para sa iyo. Hindi nagsisimula ang mga browser sa HTTP/3. Kumokonekta muna sila gamit ang HTTP/2 o HTTP/1.1, nakikita ang isang Alt-Svc: h3=":443"; ma=86400 header sa response, at ginagamit ang HTTP/3 sa mga susunod na connection sa host na iyon. Kaya hindi optional na dekorasyon ang header. Ito ang mekanismo ng discovery. Sa nginx, naging hiwalay na directive ang HTTP/2 sa version 1.25.1 (http2 on; sa loob ng server block, kapalit ng dating listen ... http2 parameter), at dumating ang QUIC sa mainline 1.25.0. Para sa HTTP/3 site, kailangan dito ang listen 443 quic reuseport; kasabay ng karaniwang listen 443 ssl;.
Magkakaiba ang maturity ng mga proxy sa bahaging ito, kaya dapat itong i-check batay sa version na aktuwal mong pinapatakbo. Noong August 2026, nagseserve ang Caddy ng HTTP/3 bilang default nang walang configuration. Kailangan ng nginx ang tahasang quic listener at ang Alt-Svc header na inilarawan sa itaas. Ine-enable ito ng Traefik bawat entry point sa pamamagitan ng tahasang http3 option. Kung nagte-terminate ka ng TLS sa Traefik sa harap ng ilang Docker app, doon napagpapasiyahan ang protocol version na matatanggap ng mga visitor, at karaniwang plain HTTP/1.1 ang hop mula sa proxy papunta sa container mo, anuman ang protocol na napili ng browser.
Mag-verify sa halip na mag-assume. Gumagana lamang ang curl --http3 -sS -o /dev/null -D - https://example.com/ kung inililista ng curl -V ang HTTP3 sa mga feature nito, at hindi ito karaniwang kasama sa mga build ng distribution. Ang maaasahang pag-check ay ang sarili mong log: idagdag ang $server_protocol sa format at basahin kung ano ang nino-negotiate ng mga aktuwal na browser. Bago ang lahat ng iyon, kumpirmahing talagang bukas ang UDP 443, dahil hahayaan ng firewall na TCP 443 lamang ang pinapahintulutan na tahimik na mabigo ang HTTP/3 habang patuloy na gumagana ang site sa HTTP/2. Ang pag-alam sa mga port na bukas at nakikinig sa iyong Linux server ang unang dapat i-check.
HTTPS: HTTP ang protocol, TLS ang wrapper
Hindi hiwalay na protocol ang HTTPS. Pareho itong mga request at status code na ipinapadala sa loob ng TLS session. Ipinapadala ang mga ito nang hindi encrypted sa port 80, at encrypted naman sa port 443. Nauuna munang matapos ang TLS handshake, saka ipinapadala ang HTTP request sa loob ng encrypted channel. Dahil dito, walang status code ang certificate problem: nangyayari ang failure bago maipadala ang kahit isang HTTP byte, kaya walang response na mabibigyan ng number.
Mahalaga ang isang detalye sa pagkakasunod-sunod kapag maraming site ang naka-host sa isang server. Pinipili ang certificate gamit ang SNI (server name indication), isang field sa TLS handshake na naglalaman ng hostname nang hindi encrypted bago pa magkaroon ng anumang HTTP header. Kaya unang pumipili ang server ng certificate mula sa SNI, at pagkatapos ay pumipili ng virtual host mula sa Host header. Magkahiwalay na lookup ang mga ito, pero karaniwan ay pareho ang resulta. Kapag hindi nagtugma ang mga ito, nagpapakita ang browser ng name mismatch gaya ng NET::ERR_CERT_COMMON_NAME_INVALID at hindi na nagpapadala ng request, dahil ang certificate ng default server mo ang naialok para sa pangalang hindi nito saklaw.
Para sa isang public site, kumuha ng tunay na certificate at hayaan itong awtomatikong mag-renew. Isinusulat ng Certbot gamit ang Let's Encrypt sa nginx ang mga path ng certificate sa server block mo at ini-install nito ang renewal timer para sa iyo. Para sa hostname na hindi ma-validate ng anumang public authority, gaya ng internal name o bare IP address sa sarili mong network, ang self-signed certificate sa Ubuntu ang tapat na opsyon, basta tanggap mong kailangang sabihan ang bawat client na pagkatiwalaan ito.
Kapag gumagana na ang TLS, ipadala ang lahat mula sa port 80 papunta sa port 443:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}Idagdag lang ang Strict-Transport-Security kapag sigurado ka na. Sinasabi ng add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; header sa mga browser na tanggihan ang plain HTTP para sa hostname na iyon sa loob ng dalawang taon, at sinusunod nila ito mula sa sarili nilang cache. Ibig sabihin, hindi ito mababawi sa simpleng pag-alis ng header sa hinaharap. Magsimula sa max-age na ilang oras, tiyaking nasa HTTPS talaga ang bawat subdomain, at saka ito taasan.
FAQ
Ano ang kaibahan ng HTTP at HTTPS?
Ang HTTPS ay HTTP na ipinapadala sa loob ng TLS (transport layer security) session. Magkapareho ang methods at status codes. Ang nagbabago ay naka-encrypt ang bytes sa pagitan ng client at ng anumang nagte-terminate ng TLS, at lumilipat ang default port mula 80 sa 443. Dahil natatapos ang TLS handshake bago maipadala ang unang HTTP byte, hindi kailanman naglalabas ng status code ang certificate failure. Kaya error name gaya ng NET::ERR_CERT_COMMON_NAME_INVALID ang ipinapakita ng browser na certificate warning, sa halip na numerong gaya ng 403.
Bakit nagbabalik ang site ko ng 502 Bad Gateway?
Ang 502 mula sa nginx ay nangangahulugang hindi nakakuha ang nginx ng magagamit na response mula sa upstream na bina-proxy nito. Ibig sabihin, maayos ang request ng bisita at may problema sa isang component sa likod ng nginx. Basahin ang /var/log/nginx/error.log. Ang connect() failed (111: Connection refused) while connecting to upstream ay nangangahulugang walang nakikinig sa address at port sa proxy_pass. Suriin kung tumatakbo ang application at naka-bind ito sa inaasahang address. Ang no live upstreams while connecting to upstream ay nangangahulugang minarkahan nang down ang bawat server sa upstream block matapos ang paulit-ulit na failure. Ikumpara ito sa 504 Gateway Timeout, na nangangahulugang tinanggap ng upstream ang connection ngunit hindi ito nakasagot sa loob ng proxy_read_timeout.
Bakit pareho ang IP address na ipinapakita ng access log ko para sa bawat bisita?
Dahil itinatala ng $remote_addr ang address na nagbukas ng TCP connection. Kapag nasa likod ng reverse proxy o content delivery network ang site, ang address na iyon ay sa proxy. Sa X-Forwarded-For header naman ipinapadala ang address ng bisita. I-set ang proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; sa proxy. Pagkatapos, sa tumatanggap na nginx, i-set ang set_real_ip_from sa address range ng proxy at i-enable ang real_ip_header X-Forwarded-For;. Ilagay lamang ang mga range na kontrolado mo. Text lamang ang header na iyon at maaaring ipadala ng anumang client. Kapag pinagkakatiwalaan ito mula sa buong internet, maaaring piliin ng bisita ang address na itatala mo at ang address na gagamitin sa rate limiting.
Kailangan ko bang i-enable ang HTTP/2 o HTTP/3?
Sulit i-enable ang HTTP/2. Isang directive lamang ito sa site na mayroon nang TLS, at inaalis nito ang per-connection request limit na nagpapabagal sa page na maraming maliliit na file. Mas maliit at mas hindi tiyak ang pakinabang ng HTTP/3. Kailangan din nito ng bukas na UDP port 443 at proxy build na may QUIC support. Tandaan na lumilipat lamang ang mga browser sa HTTP/3 matapos makakita ng Alt-Svc header sa naunang response. Kung wala ang header na iyon, walang magbabago kahit ano pa ang nasa listen line mo. Idagdag ang $server_protocol sa log format mo at sukatin kung ano talaga ang nino-negotiate ng mga bisita bago ito paglaanan ng oras.
Ano ang ibig sabihin ng 403 Forbidden kapag umiiral ang file?
Sa static site, ang 403 ay karaniwang filesystem permission issue, hindi HTTP rule. Ang open() ... failed (13: Permission denied) sa /var/log/nginx/error.log ay nangangahulugang hindi mabasa ng nginx worker user ang file. Kadalasan, kulang ng execute permission para sa others ang parent directory, sa halip na mali ang file mode mismo. Ang directory index of ... is forbidden ay nangangahulugang nag-resolve ang request sa isang directory na walang index file habang naka-off ang autoindex. Ang tahasang deny rule sa tumutugmang location block ay nagbabalik din ng 403. Kaya basahin ang block na iyon kapag walang ipinapakitang paliwanag ang error log.