--- tags: 1101_lsa --- # Web Server [TOC] :::info - 一台主機 - 可以存超級多資料 or 運算能力強大 - 可以為大量使用者提供服務 - 通常以網路作為媒介 - 有很多種類 - file server、FTP server、DNS server... - 各式各樣的伺服器提供各式各樣的功能~ - 有些伺服器提供的功能,我們幾乎天天用 - 上網查資料 - DNS server 可以透過紀錄域名讓我們不用記一串 IP 也能連到網站 - 不過是誰把網站的內容傳給我們的 ? - web server ::: ## 甚麼是 Web Server ? - 存放網路伺服器軟體、還有網站檔案的主機 - HTML、圖片、CSS、JavaScript - 透過 HTTP 將網頁資料傳給 client 端 - 通常 client 端指的是 browser (瀏覽器) - chrome、firefox... ### HTTP - **H**yper**t**ext **T**ransfer **P**rotocol - client 端和 server 端之間 request 和 response 的標準 - 透過 TCP 作為資料的傳輸方式 - 應用層的協定 - 預設使用 **80 port** 作為通訊的端點 - ![](https://i.imgur.com/qUNoozC.png) > 有興趣可以查 `http & https 的差異`,中央資管所面試有問到這個問題喔~ ## port - 埠 ( `ㄅㄨˋ` ) 號 :::info - 舉例 : 郵局 - 一間郵局有很多個窗口 - 每個窗口辦理的事項不盡相同 - 如果一號窗口是辦郵政的,你拿存款單過去就會被翻白眼然後請你離開 - 一台電腦也有很多 port (窗口) - 是系統模擬出來的 port 不是網路孔的 port - 這些虛擬的 port 可以供各種服務使用 - 0 ~ 65535 個 port - 每個 port 提供的特定服務 - 想 ssh 就使用 22 port,看網頁就使用 80 port ::: ### why we need port ? - 電腦上很多運行的服務會用網路傳輸資料 - chrome、telegram、game... - 這麼多的資料混在一起,電腦該怎樣分出哪些資料是誰的呢? - 大亂鬥,本來要傳給 telegram 的封包,結果被送到 line 那邊去 - 封包回傳到電腦的時候,會標記要給哪個 port - 電腦就會把這個封包分配到目前占用該 port 的服務 - 這樣就知道這個封包是要傳給誰的了~ <!-- - TCP 的 Header 有 Source Port 跟 Destination Port --> <!-- - 電腦不斷的往網路上傳送訊息,也不斷的接收訊息。 --> <!-- - 標識伺服器上提供的特定網路服務 - client 可以按照 server IP 與 port 與相應的 server service 建立網路連接,獲得相應的網路服務。 --> ### 介紹 - port number 以 16 bits 來表示 - 共有 65536 個 port 可使用 (2^16) - 0 - 保留通訊埠,平常不會啟用 - 1 ~ 1023 需**超級使用者權限**才能占用這些 port - 主要是用於一些常見的通訊服務 - ![](https://i.imgur.com/gh16rVL.png =550x) - 1024 以上,不需超級使用者權限就能占用這些 port - 供其他用途使用 - mysql:3306 - ms-wbt-server:3389 - Windows RDP (Remote Desktop Protocol) - `/etc/services` - 紀錄各式各樣服務會占用的 port 號 - service name, port number, Protocol used, aliases :::info **IANA** - Internet Assigned Numbers Authority - 管理即維護 Domain Names、Number Resources、Protocol Assignments 的非營利組織 - 定義 port number 註冊表 ::: :::info **小 demo** - `netstat -antupl` - 打開 firefox - 本機到 Local Address 接收 Foreign Address 傳過來的封包 ::: :::warning [**DNS**](https://hackmd.io/e5amkx_9TVyrTHjkm2902w?view) - 用 telnet 上網 - 瀏覽器上網按 enter 的過程 ::: ### 有哪些 Web Server - 有很多種伺服器軟體 - webserver 的功能都大同小異 - 但各有特性 - lighttpd - 適合做檔案傳輸 - file server - 占用系統資源少 - 運作起來較輕量 - 設定簡單 - apache (遠古巨獸) - 歷史最悠久 - 以前市占率最高 - 2019 年開始被 nginx 超車 - 模組功能強大 - 因為外掛模組多,常常伴隨安全性弱點 - 占用系統資源多 - 巨肥 - 設定最麻煩的 - nginx - 可同時乘載很大的流量 - 連線數的乘載率高,且速度快 :::danger 既然 lighttpd 設定簡單,那我們就先從 lighttpd 開始說起 ::: ## lighttpd :::danger 目前大家在使用的 taiwan ubuntu apt 來源站架設的 web server 就是使用 lighttpd ::: ### 安裝 - `sudo apt install lighttpd` ### 啟動 - `sudo service lighttpd status` - 預設自動開啟 - `sudo netstat -ntupl` - 看一下 run 在哪個 port :::warning 可以補充一下 netstat 有沒有 sudo 的差別 - 因為要看那些 process 的 pid & process_name 補充 : 改主設定檔前,要先把 service stop ::: :::danger - lighttpd 只要是設定檔,都放在 `conf-available` - vhost、一般設定檔...都放在這 ::: - `cat /etc/lighttpd/lighttpd.conf` - server.modules : 預設啟動哪些模組 - server.document-root : 網頁的根目錄位置 - server.errorlog - server.username & groupname : 執行 lighttpd 後切換到哪個使用者權限 - `www-data` : 可以在 /etc/passwd 找到 - 一個 system user - 專門給 web server 使用的特定 user/group - 主要希望 web server 不要有太高的權限,但同時讓 web application 適當進行寫入。 - server.port - index-file.names : 紀錄有哪些預設的頁面 :::danger - 我們連上 google.com 的時候,後面就直接 / 結尾,此時沒有接其他東西,對方要怎麼知道要傳甚麼網頁給我看 ? - `/` 是目錄的意思,我們總不希望連到 google.com 他給我看底下有那些目錄跟檔案,希望他給我們看漂漂亮的頁面 - 當 web server 發現,我們要存取一個目錄時,能有預設的檔案可以顯示 - index-file.names 就是紀錄有哪些預設的頁面可以顯示 :::info **小 demo** - `sudo service lighttpd stop` - 在 index-file.names 最前面加一個 lighttpd.html - 到 document-root 底下新增 lighttpd.html - `sudo vim /var/www/lighttpd.html` ```html= This is lighttpd WELCOME PAGE ! ``` - `sudo service lighttpd start` ::: :::danger - 如果沒有 access-deny 的話會發生甚麼事 - 在一些 .php 型的網頁中,會用 .inc 檔來儲存與 DB 連線的 IP、帳密 - 有人在伺服器上直接改檔案時,會留下有 `~` 符號作為前置/後綴的檔名作為暫存檔 - 如果這些東西使用者可以直接存取的話非常危險 - 帳密直接給別人看怎麼行 - 所以設定 access-deny 來過濾檔名有包含 `~` 或 `.inc` 的 request - 告訴使用者無法存取,避免資訊外洩 - 如果沒有 static-file.exclude-extensions 的話會發生甚麼事 - 當有一些特定模組沒有被啟動或有設定檔設定失誤的時候,所有的檔案,都會被當作 static file - static file: 可被下載的檔案 - .html、.jpg - 使用者就可以直接看到 .php 的 sourcecode - 因為 .php 變成 static file 就可以下載 - 有可能就會被從程式碼中找 bug 或直接找到帳密資訊 - 所以設定 exclude-extensions 來告訴 web server,這些副檔名的檔案,不能被當作 static file ::: - access-deny : 讓使用者無法存取特定檔案 - static-file.exclude-extensions : 哪些副檔名的檔案,不能被當作 static file - compress.cache-dir : 壓縮的檔案存在哪裡 - 自動壓縮,不過要有啟動 module 才會自動壓縮 - ![](https://i.imgur.com/W8s03vI.png =300x) - compress.filetype : 要壓縮那些檔案 - 通常是 Javascript, CSS, HTML... :::info **為什麼預設啟動 web server 要用 sudo** - 這些 web server 預設占用 80 port - 80 port 需要超級使用者權限才能占用 - 再來啟動完之後要切換使用者 - 超級使用者才能切換使用者帳號 - 有些檔案需要超級使用者權限才能查看 - `/var/www/html`、`/var/log/` - 所以如果把 port 改成 8080,user/group name 改成自己,pid、log file...檔案路徑都改成自己可以寫入讀取的路徑 - 就可以不需要超級使用者權限就可以啟動服務 ::: <!-- :::info - 開啟 browser 連進 localhost 查看結果 - 如果結果是 Apache2 Ubuntu Default Page - `cat /etc/lighttpd/lighttpd.conf` - server.document-root - index-file.names - 去看看 `/var/www/html` 有沒有 `index.html` - `cat /var/www/html/index.html` - 內容會是 Apache2 Default Page - 原因可能是 `apt install` 時發現已經有 index.html 所以被 ignore ::: --> - `sudo netstat -ntupl` - lighttpd 占用 80 port - 如何將 lighttpd 設定檔 enable & disable - `lighty-enable-mod` - ![](https://i.imgur.com/chcWGGa.png) - 一開始是告訴你有哪些 modules disable,那些 enable - 接下來可以輸入要 enable 的 module name - `lighty-disable-mod` - 可以輸入要 disable 的 module name - 也可以直接在指令後面空格接 module name - 要 run `sudo service lighttpd force-reload` 才會被 lighttpd 吃到修改後的設定檔 - 其實他只是幫忙自動建 link 到 conf-enable 裡 ### 設定 port 為 8080 - `sudo service lighttpd stop` - `ls -al /etc/lighttpd/` - 看 `lighttpd.conf` - `sudo vim /etc/lighttpd/lighttpd.conf` - server.port - 改成 8080 port - `sudo service lighttpd start` - 打開 browser 連進 localhost - 會連不進去(因為沒有服務占用 80 port) - localhost:8080 - `sudo netstat -ntupl` - lighttpd 跑在 8080 port ## apache2 :::danger 為什麼不直接講 apache 要叫他 apache2 呢 2 只是他的版本號,在之前的 apache 最常用 ver 1.3,只是更新了,就變 ver 2 了,不過本質都是 apache apache 是其中一種美國原住民部落,好像目前美國仍有幾個 apache 部落 ::: ### 安裝 - `sudo apt install apache2` ### 啟動 - `sudo service apache2 status` - 開啟 browser 連進 localhost 查看結果 - 會出現 Apache2 Ubuntu Default Page - `sudo netstat -ntupl` - apache 占用 80 port - `apache2.conf` - user、group - /etc/apache2/envvars : 存環境變數 - ErrorLog - Include ports.conf - IncludeOptional - ![](https://i.imgur.com/mj5sYY4.png =500x) - ![](https://i.imgur.com/XLpQ5Bw.png =500x) - 跟 lighttpd 有點不同,module、一般設定檔、virtual host 的相關設定是分開的 ### 設定 port 為 8081 - `sudo service apache2 stop` - 為了保險起見,要改設定檔前,先將 server 關掉 - apache2 超多設定檔 - `ls -al /etc/apache2` - 看一下 `apache2.conf` - ![](https://i.imgur.com/HCIhHgI.png =500x) - apache 監聽的 port 號是看 `ports.conf` - `sudo vim port.conf` - 因為是 /etc/ 底下的設定檔,稍有不慎,服務可能再也啟動不起來,所以沒有超級使用者權限無法設定 - ![](https://i.imgur.com/73HQIID.png) - 預設是 80 port - 改監聽 8081 - `sudo service apache2 start` - 可以看一下 status 是不是 Active - 打開 browser 連進 localhost - 會連不進去(因為預設 80 port) - localhost:8081 就可以連進去 - `sudo netstat -ntupl` - apache 確實跑在 8081 port ## Nginx :::danger nginx 是目前最多站點使用的 web server,wiki 就是其中一個 nginx 在開發時,目標很明確,就是各方面比 apache 好就對了 所以 nginx 占用的系統資源跟處裡 request 的速度確實都比 apache 好很多 ::: ### 安裝 - `sudo apt install nginx` - `sudo service nginx status` - 打開 browser 連進 localhost - Welcome to nginx! ### 看一下設定檔 - nginx 的設定檔主要放在 3 個地方 - 方便管理 - 避免系統更新的時候把設定檔改掉 - 將系統的設定檔,與使用者定義的設定檔分開 - 井水不犯河水 - `nginx.conf`、`sites-available`、`sites-enabled` - `nginx.conf` - nginx 的主設定檔 - 沒事不要動它 - 讓主設定檔跟著系統更新 - 如果要改,也可以改完放在 conf.d 裡面 - worker_processes = 可以開幾個 process - 能開幾個 process 取決於 CPU core 數量 :::info **小 demo** - sudo service nginx stop - worker_processes 3; - sudo service nginx start - sudo service nginx status - ![](https://i.imgur.com/BgZMHF3.png) ::: - log 存在哪 - ![](https://i.imgur.com/7ZcRte0.png =500x) - 會吃哪些設定檔 - ![](https://i.imgur.com/gEARzc6.png =500x) > FIXME: sendfile、SSL Settings、gzip > tcp_nopush on; > 19 tcp_nodelay on; > 20 keepalive_timeout 65; :::info keepalive (上學期查的一點咚咚) - 用於監測兩個設備之間的網路連線是否正常,或防止連線中斷 - Keepalive time : 預設值 7200 秒(2 小時) - Keepalive interval : 75 秒 - Keepalive retry : 9 次 - tcp_keepalive_time 的 7200 秒指的是 “idle" connection, 就是兩邊都沒傳資料過兩小時會開始送第一個 tcp probe (探測封包) ::: - `sites-available` & `sites-enabled` - 為了避免在系統設定時互相影響,所以區隔成兩個目錄 - `sites-available` 設定檔集中地 - 方便管理 - `enabled` 需 link 到 `available` 的設定檔才能使用 - `sites-enabled` 會被服務運行的設定檔 - 這個目錄底下的設定檔如果有改,需要用 reload 才能讓 nginx 重新載入設定檔 - 設定才能生效 ### default site (80) - `ls -l /etc/nginx/sites-available` - 看一下目前 nginx 有甚麼設定檔 - default - `cat /etc/nginx/sites-available/default` :::success **Config** - listen {port} - 監聽哪個 port (IPv4) - 其實是 listen ip:{port},如果沒有 ip 就是誰來就聽 - listen [::]:{port} - 監聽哪個 port (IPv6) - default_server : 找不到對應的 virtual host 連線時,就連 default_server 的 index file - root {path} - 網頁的根目錄 - index {fileName} - 當使用者==沒有指定==要連到這個目錄的哪個檔案時 - 預設依照 index 依序搜尋檔案存不存在 - 存在就連線 - 不存在就 `403 Forbidden` :::danger 輸入無效的 URL 不讓你連線喔 ::: - server_name {DomainName} - location / {} - 定義對特定路徑的操作 - `try_files` 搜尋步驟 - 假設我想連到 `/keke` - 會先檢查 /keke 是不是檔案 - 是就連線 - 不是就下一步 - 檢查有沒有 /keke/ 這個資料夾 - 有的話,就連進目錄 - 做上方找 index 的步驟 - 沒有就下一步 - 非常遺憾,`/keke` 不是檔案也不是資料夾,回傳 `404 Not found` - location ~ \\.php$ {} - `~ \.php$` - 正規表示式 - 符合結尾是 .php 的路徑 - 會額外啟動 `fastcgi` 或 `fpm` - `fastcgi` 跟 `fpm` 是專門用來解析跟執行 php 的服務 - 會把這個路徑的需求,轉給 `fastcgi` 跟 `fpm` 執行,執行完再傳給 nginx ,然後 nginx 回傳給 client - `location ~ /\.ht` - deny all; - 只要是符合 `/.ht` 字串的路徑,就不給連線 - rewrite {正規表示式} - redirect 到後面接的網址 ::: :::danger default_server & server name - server name 是用來跟使用者傳來的 http request 中的 Host header 做比對 - 比對 virtual host 中有沒有對應的 server name - 有的話就連到這台 virtual host - 沒有的話,就去找有沒有 default server - 有 default server 的話,server name 就不重要了 - 因為沒有對應的 virtual host 所以連到 default server 就對了 - 可以用 telnet 做小 demo - telnet localhost 80 - get / http/1.1 - Host: asdf - 會連到 defualt_server 的 index file ::: - `sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.backup` - 可以先建議大家複製一份起來,改壞了才有救 ### virtual host (81) - 一台或多台 host 共享資源提供多個服務 - 可以同一機器上運行多個網站 - 以 domain_name, port, IP 等訊息做區隔 - 依據使用者的訊息提供不同的內容 - 怎麼設定呢 ? - 就跟設定剛剛的 default config 一樣 #### name base - 前面提到一串 IP 很難記,所以有了 DomainName 輔助我們,那有個設定檔紀錄 DomainName 對應 IP - `/etc/hosts` - 到 `/etc/hosts` 新增一個 DomainName - `127.0.0.1 nginx1.com` - 跟剛剛一樣的步驟,到 `/var/www/vhost/nginx1` 建等等要連進去的網站 - `sudo vim /var/www/vhost/nginx1/name.html` ```html= This is nginx NAME base Virtual Host!!! ``` - 回到 `/etc/nginx/sites-available/` 設定相關檔案 - `sudo vim /etc/nginx/sites-available/nameBase` ```s= server { listen 81; server_name nginx1.com; root /var/www/vhost/nginx1; index name.html; location / { try_files $uri $uri/ =404; } } ``` - Soft Link 到 `nginx/sites-enabled/` - `sudo ln -s /etc/nginx/sites-available/nameBase /etc/nginx/sites-enabled/` - 確認設定檔有沒有問題 - `sudo nginx -t` - 沒有問題的話就 reload - `sudo service nginx reload` - 測試時間~ - nginx1.com:81 會看到 `name.html` --- #### port base - 跟剛剛一樣的步驟,到 `/var/www/vhost/nginx1` 建等等要連進去的網站 - `sudo vim /var/www/vhost/nginx1/port.html` ```html= This is nginx PORT base Virtual Host!!! ``` - sudo vim /etc/nginx/sites-available/portBase ```s= server { listen 82; server_name nginx1.com; root /var/www/vhost/nginx1; index port.html; location / { try_files $uri $uri/ =404; } } ``` - Soft Link 到 `nginx/sites-enabled/` - 確認設定檔有沒有問題 - 沒有問題的話就 reload - 測試時間~ - nginx1.com:82 會看到 `port.html` ### Reverse Proxy :::danger 前面提到 nginx 乘載量大,所以它適合用來 reverse proxy ::: - 舉例 : 問 BT 問題 - 學生 ABC 問 BT webserver 的問題 - 因為是 keke 做的,所以 BT 問完 keke 後才回應 ABC - 但 keke 不知道有那些學生有問問題,只知道 BT 問我問題 - 學生 A 問 BT 買樹莓派的問題 - 有好多個助教,因為是 ㄅ瑋 負責的,所以 BT 問完ㄅ瑋後才回應 A - 但 A 不知道是哪個助教解答問題,只知道 BT 回答問題 - proxy : 代理 - 幫使用者**代理**連到目標網站,再把網站內容傳回來給使用者,server 不知道是哪個使用者要了資料 - reverse proxy : 反向代理 - 但使用者不知道 proxy server 連到哪台主機抓資料 - 好處 - 以後有問題就問 BT 就對了~ - 不需要知道問哪個助教,只要問 BT 他就會跟你說 - server IP 可以不用讓使用者知道,proxy server 自己會處理 - eg. 我想把 apache 從 8080 換到 8081,client 端不用改變設定,只需更改 reverse proxy 就好 - 適合 Load balance - Reverse Proxy 可以決定給哪個 Server 處理請求,看誰最閒或是輪流也可以 - BT 看到大家都在問蔣媽問題,所以後來有人問問題,就請同樣會但有空的子瑋代理回答 - 用 nginx reverse proxy 到 apache(8081) 跟 lsa.kija.io --- - 到 `/etc/hosts` 新增一個 DomainName - `127.0.0.1 nginx1.proxy.com` - 回到 `/etc/nginx/sites-available/` 設定相關檔案 - `sudo vim /etc/nginx/sites-available/nginx_proxy` ```s= server { listen 80; server_name nginx1.proxy.com; location / { proxy_pass http://localhost:8081; } } ``` - Soft Link 到 `nginx/sites-enabled/` - `sudo ln -s /etc/nginx/sites-available/nginx_proxy /etc/nginx/sites-enabled/` - 確認設定檔有沒有問題 - `sudo nginx -t` - 沒有問題的話就 reload - `sudo service nginx reload` - 測試時間~ - nginx1.proxy.com:80 會看到 apache --- - 也可以 proxy 到外部網站 ```s= server { listen 80; server_name nginx1.proxy.com; location / { proxy_pass http://lsa.kija.io; } } ``` ### load balance - 負載平衡 : 將流量合理分配,以提升可用性(提升資源使用率),避免機器過載的技術 - 舉例 : 教室 - LSA 上課開了 3 間教室 - 一間教室坐 20 人 - 大家來上課,因為第一間教室離大門進,大家都走進第一間教室 - 結果第一間教室都坐滿了,卻還是一直有人走進去看 - 走廊就塞住了,因為走進去發現沒位置只好走出來 - 助教看不下去了,就在大家的必經之路跟其他學生說第一間教室滿了,請大家直接到第二間教室喔~ - 分流~ - 將流量合理分配給其他 server - 避免流量其中在同一台 server 導致服務無法正常運行 - 也避免明明有 server 開著卻沒有在執行服務 - nginx 模擬 load balance 的效果 --- - 到 `/etc/hosts` 新增一個 DomainName - `127.0.0.1 nginx1.loadB.com` - 到 `/etc/nginx/sites-available/` 設定相關檔案 - `sudo vim /etc/nginx/sites-available/nginx_loadB` ```s= upstream lsa.lab { server localhost:8080; server localhost:8081; } server { listen 80; server_name nginx1.loadB.com; location / { proxy_pass http://lsa.lab; } } ``` > FIXME: 在 location 裡面加多個 proxy_pass 會怎樣 ? 或加 array >> 都會噴錯,在一台 server 只能 proxy_pass 到一個網站 :::info **upstream** - 紀錄要分流的 IP - 後面接的名稱單純變數名稱,隨便命名沒關係 - 預設使用 round-robin 來分配流量 ::: - Soft Link 到 `nginx/sites-enabled/` - `sudo ln -s /etc/nginx/sites-available/nginx_loadB /etc/nginx/sites-enabled/` - 確認設定檔有沒有問題 - `sudo nginx -t` - 沒有問題的話就 reload - `sudo service nginx reload` - 測試時間~ - nginx1.loadB.com:80 會看到 apache 跟 lighttpd - 瘋狂 `F5` :::info **service** - `sudo service <service_name> <操作>` - `status` 查看狀態 - `start` 開啟服務 - `stop` 關閉服務 - `reload` 不停止服務,重載設定檔 - `force-reload` 只是 `reload` 的 alias,功能一樣 - `restart` 停止服務重新開啟 - `sudo /etc/init.d/<service_name> <操作>` - `/etc/init.d/` : 存放系統服務啟動時的設定檔 - `service` 其實是到這裡找設定檔 - `sudo systemctl <操作> <service_name>` - 會到 `/lib/systemd/system` 找對應的檔案 - service & systemctl different - systemctl 能做的事比 service 多 - service 只能做簡單的操作 - start、restart、reload... - systemctl 提供更多操作指令 - is-failed、reload-or-restart... ::: :::warning **備註** - https://www.ptt.cc/man/Ladies_Digi/DE82/D9D8/M.1153022568.A.D3B.html - 打指令 都打絕對路徑 - link 檔要 link 到對的地方 ~ - https://www.reddit.com/r/pihole/comments/a8os8b/no_default_indexlighttpdhtml/ :::