Lwan เป็นเว็บเซิร์ฟเวอร์ ที่มีประสิทธิภาพสูง และ ปรับขนาดได้
เว็บไซต์โครงการมีรายละเอียดเพิ่มเติม
| ระบบปฏิบัติการ | โค้ง | ปล่อย | การดีบัก | การวิเคราะห์แบบคงที่ | การทดสอบ |
|---|---|---|---|---|---|
| ลินเวกซ์ | x86_64 | ประวัติรายงาน | |||
| FreeBSD 14 | x86_64 | ||||
| OpenBSD 7.4 | x86_64 |
คุณสามารถสร้าง Lwan ด้วยตัวเองใช้ภาพคอนเทนเนอร์หรือคว้าแพ็คเกจจากการแจกจ่ายที่คุณชื่นชอบ
ก่อนที่จะติดตั้ง LWAN ให้ตรวจสอบให้แน่ใจว่ามีการติดตั้งการพึ่งพาทั้งหมด พวกเขาทั้งหมดเป็นสิ่งที่พบได้ทั่วไปในการแจกแจง GNU/Linux ใด ๆ ชื่อแพ็คเกจจะแตกต่างกัน แต่ไม่ควรค้นหาโดยใช้เครื่องมือจัดการแพ็คเกจที่ใช้โดยการแจกแจงของคุณ
ระบบบิลด์จะค้นหาไลบรารีเหล่านี้และเปิดใช้งาน/ลิงก์หากมี
-DENABLE_BROTLI=NO-DENABLE_ZSTD=NO-DENABLE_TLS=ON (ค่าเริ่มต้น) จะผ่าน:-DUSE_ALTERNATIVE_MALLOC ไปยัง CMAKE ด้วยค่าต่อไปนี้:pacman -S cmake zlibpkg install cmake pkgconfapt-get update && apt-get install git cmake zlib1g-dev pkg-configbrew install cmake pacman -S cmake zlib sqlite luajit mariadb-libs gperftools valgrind mbedtlspkg install cmake pkgconf sqlite3 lua51apt-get update && apt-get install git cmake zlib1g-dev pkg-config lua5.1-dev libsqlite3-dev libmariadb-dev libmbedtls-devbrew install cmake mariadb-connector-c sqlite [email protected] pkg-config ~$ git clone git://github.com/lpereira/lwan
~$ cd lwan
~/lwan$ mkdir build
~/lwan$ cd build
การเลือก เวอร์ชัน รุ่น (ไม่มีสัญลักษณ์การดีบักข้อความเปิดใช้งานการเพิ่มประสิทธิภาพบางอย่าง ฯลฯ ):
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=Release
หากคุณต้องการเปิดใช้งานการเพิ่มประสิทธิภาพ แต่ยังคงใช้ดีบั๊กให้ใช้สิ่งนี้แทน:
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
เพื่อปิดใช้งานการเพิ่มประสิทธิภาพและสร้างเวอร์ชันที่เป็นมิตรกับการดีบักมากขึ้น:
~/lwan/build$ cmake .. -DCMAKE_BUILD_TYPE=Debug
~/lwan/build$ make
สิ่งนี้จะสร้างไบนารีสองสามครั้ง:
src/bin/lwan/lwan : LWAN หลักปฏิบัติการได้ อาจถูกดำเนินการด้วย --help ช่วยขอคำแนะนำsrc/bin/testrunner/testrunner : มีรหัสเพื่อเรียกใช้ชุดทดสอบ ( src/scripts/testsuite.py )src/samples/freegeoip/freegeoip : การใช้งานตัวอย่าง freegeoip ต้องใช้ sqlitesrc/samples/techempower/techempower : รหัสสำหรับเกณฑ์มาตรฐาน Web Framework TechEmpower ต้องใช้ห้องสมุด SQLite และ Mariadbsrc/samples/clock/clock : ตัวอย่างนาฬิกา สร้างไฟล์ GIF ที่แสดงเวลาท้องถิ่นเสมอsrc/bin/tools/mimegen : สร้างตารางประเภทส่วนขยาย-เวลา ใช้ในระหว่างกระบวนการสร้างsrc/bin/tools/bin2hex : สร้างไฟล์ C จากไฟล์ไบนารีเหมาะสำหรับใช้กับ #include ใช้ในระหว่างกระบวนการสร้างsrc/bin/tools/configdump : ทิ้งไฟล์กำหนดค่าโดยใช้ API ตัวอ่านการกำหนดค่า ใช้สำหรับการทดสอบsrc/bin/tools/weighttp : การเขียนใหม่ของเครื่องมือการเปรียบเทียบ weighttp HTTPsrc/bin/tools/statuslookupgen : สร้างตารางแฮชที่สมบูรณ์แบบสำหรับรหัสสถานะ HTTP และคำอธิบายของพวกเขา ใช้ในระหว่างกระบวนการสร้าง การผ่าน -DCMAKE_BUILD_TYPE=Release จะเปิดใช้งานการเพิ่มประสิทธิภาพคอมไพเลอร์ (เช่น LTO) และปรับรหัสสำหรับสถาปัตยกรรมปัจจุบัน
สำคัญ
โปรดใช้บิลด์รีลีสเมื่อทำการเปรียบเทียบ ค่าเริ่มต้นคือบิลด์ดีบั๊กซึ่งไม่เพียง แต่บันทึกคำขอทั้งหมดไปยังเอาต์พุตมาตรฐาน แต่ทำเช่นนั้นในขณะที่ถือล็อคอย่างรุนแรงถือเซิร์ฟเวอร์ไว้อย่างรุนแรง
บิลด์เริ่มต้น (เช่นไม่ผ่าน -DCMAKE_BUILD_TYPE=Release ) จะสร้างเวอร์ชันที่เหมาะสมสำหรับวัตถุประสงค์ในการดีบัก รุ่นนี้สามารถใช้ภายใต้ Valgrind (หากมีส่วนหัว) และรวมถึงข้อความการดีบักที่ถูกถอดออกในเวอร์ชันรุ่น ข้อความการดีบักจะถูกพิมพ์สำหรับแต่ละคำขอ
ในการสร้างเหล่านี้สามารถเปิดใช้งาน sanitizers หากต้องการเลือกที่จะสร้าง LWAN ด้วยให้ระบุหนึ่งในตัวเลือกต่อไปนี้ไปยังสายเรียกร้อง CMAKE:
-DSANITIZER=ubsan เลือกยาฆ่าเชื้อพฤติกรรมที่ไม่ได้กำหนด-DSANITIZER=address เลือกที่อยู่ฆ่าเชื้อ-DSANITIZER=thread เลือกเกลียวเกลียว การจัดสรรหน่วยความจำทางเลือกสามารถเลือกได้เช่นกัน ปัจจุบัน Lwan รองรับ TCMALLOC, MIMALLOC และ JEMALLOC ออกจากกล่อง หากต้องการใช้หนึ่งในนั้นให้ผ่าน -DALTERNATIVE_MALLOC=name ไปยังบรรทัดการเรียกใช้ CMake โดยใช้ชื่อที่ให้ไว้ในส่วน "การพึ่งพาตัวเลือก"
ตัวเลือก -DUSE_SYSLOG=ON สามารถส่งผ่านไปยัง CMAKE เพื่อบันทึกไปยังบันทึกระบบนอกเหนือจากเอาต์พุตมาตรฐาน
หากคุณกำลังสร้าง Lwan สำหรับการแจกจ่ายคุณควรใช้ตัวเลือก -DMTUNE_NATIVE=OFF ฉะนั้นไบนารีที่สร้างขึ้นอาจล้มเหลวในการทำงานบนคอมพิวเตอร์บางเครื่อง
การสนับสนุน TLS ถูกเปิดใช้งานโดยอัตโนมัติเมื่อมีการติดตั้ง MBEDTLS ที่เหมาะสมบนระบบ Linux พร้อมส่วนหัวใหม่พอที่จะรองรับ KTLs แต่สามารถปิดการใช้งานได้โดยผ่าน -DENABLE_TLS=NO to CMake
~/lwan/build$ make testsuite
สิ่งนี้จะรวบรวมโปรแกรม testrunner และดำเนินการชุดทดสอบการถดถอยใน src/scripts/testsuite.py
~/lwan/build$ make benchmark
สิ่งนี้จะรวบรวม testrunner และดำเนินการสคริปต์มาตรฐาน src/scripts/benchmark.py
Lwan ยังสามารถสร้างด้วยประเภทการสร้างความครอบคลุมโดยการระบุ -DCMAKE_BUILD_TYPE=Coverage สิ่งนี้ช่วยให้ผู้ generate-coverage เป้าหมายซึ่งจะเรียกใช้ testrunner เพื่อจัดทำรายงานความครอบคลุมการทดสอบด้วย LCOV
การกระทำทุกอย่างในที่เก็บนี้จะก่อให้เกิดการสร้างรายงานนี้และผลลัพธ์จะเปิดเผยต่อสาธารณชน
ตั้งค่าเซิร์ฟเวอร์โดยแก้ไข lwan.conf ที่ให้ไว้; รูปแบบมีการอธิบายในรายละเอียดด้านล่าง
บันทึก
Lwan จะพยายามค้นหาไฟล์การกำหนดค่าตามชื่อที่เรียกใช้งานได้ในไดเรกทอรีปัจจุบัน testrunner.conf จะใช้สำหรับ testrunner binary, lwan.conf สำหรับ lwan binary และอื่น ๆ
ไฟล์การกำหนดค่าถูกโหลดจากไดเรกทอรีปัจจุบัน หากไม่มีการเปลี่ยนแปลงในไฟล์นี้การเรียกใช้ LWAN จะให้บริการไฟล์คงที่ที่อยู่ในไดเรกทอรี ./wwwroot Lwan จะฟังบนพอร์ต 8080 ในทุกส่วนต่อประสาน
LWAN จะตรวจจับจำนวน CPU จะเพิ่มจำนวนตัวอธิบายไฟล์แบบเปิดสูงสุดและโดยทั่วไปแล้วจะพยายามอย่างดีที่สุดในการตรวจจับการตั้งค่าที่เหมาะสมโดยอัตโนมัติสำหรับสภาพแวดล้อมที่ทำงานอยู่ การตั้งค่าเหล่านี้จำนวนมากสามารถปรับแต่งได้ในไฟล์การกำหนดค่า แต่โดยปกติแล้วจะเป็นความคิดที่ดีที่จะไม่ยุ่งกับพวกเขา
เคล็ดลับ
เป็นทางเลือกที่ lwan ไบนารีสามารถใช้สำหรับไฟล์สแตติกเดียวที่ให้บริการโดยไม่มีไฟล์การกำหนดค่าใด ๆ เรียกใช้ด้วย --help เพื่อขอความช่วยเหลือ
LWAN ใช้ key = value ความคิดเห็นได้รับการสนับสนุนด้วยอักขระ # (คล้ายกับสคริปต์เชลล์, Python และ Perl) ส่วนที่ซ้อนกันสามารถสร้างได้ด้วยวงเล็บหยิก ส่วนอาจว่างเปล่า ในกรณีนี้วงเล็บหยิกเป็นทางเลือก
some_key_name เทียบเท่ากับ some key name ในไฟล์การกำหนดค่า (ตามรายละเอียดการใช้งานตัวเลือกการกำหนดค่าการอ่านรหัสจะได้รับเฉพาะรุ่นที่มีขีด จำกัด )
เคล็ดลับ
ค่าสามารถมีตัวแปรสภาพแวดล้อม ใช้ไวยากรณ์ ${VARIABLE_NAME} ค่าเริ่มต้นสามารถระบุได้ด้วยลำไส้ใหญ่ (เช่น ${VARIABLE_NAME:foo} ซึ่งประเมินเป็น ${VARIABLE_NAME} หากตั้งค่าหรือ foo เป็นอย่างอื่น)
sound volume = 11 # This one is 1 louder
playlist metal {
files = '''
/multi/line/strings/are/supported.mp3
/anything/inside/these/are/stored/verbatim.mp3
'''
}
playlist chiptune {
files = """
/if/it/starts/with/single/quotes/it/ends/with/single/quotes.mod
/but/it/can/use/double/quotes.s3m
"""
}
ตัวอย่างบางส่วนสามารถพบได้ใน lwan.conf และ techempower.conf
ค่าคงที่สามารถกำหนดและนำกลับมาใช้ใหม่ได้ตลอดทั้งไฟล์การกำหนดค่าโดยระบุไว้ในส่วนค่า constants ที่ทุกที่ในไฟล์การกำหนดค่า ค่าคงที่จะพร้อมใช้งานหลังจากส่วนนั้นกำหนดค่าคงที่เฉพาะ ค่าคงที่สามารถกำหนดได้อีกครั้ง หากไม่ได้กำหนดค่าคงที่ค่าของมันจะได้รับจากตัวแปรสภาพแวดล้อม หากไม่ได้กำหนดไว้ในส่วน constants หนึ่งหรือในสภาพแวดล้อม Lwan จะยกเลิกด้วยข้อความแสดงข้อผิดพลาดที่เหมาะสม
constants {
user_name = ${USER}
home_directory = ${HOME}
buffer_size = 1000000
}
ไวยากรณ์เดียวกันสำหรับค่าเริ่มต้นที่ระบุข้างต้นนั้นถูกต้องที่นี่ (เช่นการระบุ user_name เป็น ${USER:nobody} จะตั้งค่า ${user_name} เป็น nobody ถ้า ${USER} ไม่ได้ตั้งค่าในตัวแปรสภาพแวดล้อม
| พิมพ์ | คำอธิบาย |
|---|---|
str | ข้อความแบบฟรีแบบใด ๆ โดยปกติแล้วแอปพลิเคชันเฉพาะ |
int | จำนวนเต็ม ช่วงคือแอปพลิเคชันเฉพาะ |
time | ช่วงเวลา ดูตารางด้านล่างสำหรับหน่วย |
bool | ค่าบูลีน ดูตารางด้านล่างสำหรับค่าที่ถูกต้อง |
สามารถระบุฟิลด์เวลาโดยใช้ตัวคูณ สามารถระบุได้หลายครั้งพวกเขาเพิ่งรวมเข้าด้วยกัน ตัวอย่างเช่น "1M 1W" ระบุ "1 เดือนและ 1 สัปดาห์" (37 วัน) ตารางต่อไปนี้แสดงรายการตัวทวีคูณที่รู้จักทั้งหมด:
| ตัวคูณ | คำอธิบาย |
|---|---|
s | ไม่กี่วินาที |
m | นาที |
h | ชั่วโมง |
d | วัน |
w | 7 วันสัปดาห์ |
M | 30 วันเดือน |
y | 365 วันปี |
บันทึก
ตัวเลขที่มีตัวคูณที่ไม่ได้อยู่ในตารางนี้จะถูกละเว้น คำเตือนจะออกขณะอ่านไฟล์การกำหนดค่า ไม่มีช่องว่างใด ๆ ระหว่างจำนวนและตัวคูณ
| ค่าที่แท้จริง | ค่าเท็จ |
|---|---|
| หมายเลขจำนวนเต็มใด ๆ ที่แตกต่างจาก 0 | 0 |
on | off |
true | false |
yes | no |
โดยทั่วไปเป็นความคิดที่ดีที่จะให้ Lwan ตัดสินใจการตั้งค่าที่ดีที่สุดสำหรับสภาพแวดล้อมของคุณ อย่างไรก็ตามไม่ใช่ทุกสภาพแวดล้อมที่เหมือนกันและไม่สามารถใช้งานได้ทั้งหมดโดยอัตโนมัติดังนั้นจึงมีตัวเลือกการกำหนดค่าบางอย่าง
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
keep_alive_timeout | time | 15 | หมดเวลาเพื่อให้การเชื่อมต่อมีชีวิตอยู่ |
quiet | bool | false | ตั้งค่าเป็นจริงเพื่อไม่พิมพ์ข้อความการดีบักใด ๆ มีผลเฉพาะในการสร้าง |
expires | time | 1M 1w | ค่าของส่วนหัว "หมดอายุ" ค่าเริ่มต้นคือ 1 เดือนและ 1 สัปดาห์ |
threads | int | 0 | จำนวนเธรด I/O ค่าเริ่มต้น (0) คือจำนวน CPU ออนไลน์ |
proxy_protocol | bool | false | เปิดใช้งานโปรโตคอลพร็อกซี รองรับรุ่นที่ 1 และ 2 เปิดใช้งานการตั้งค่านี้หากใช้ Lwan หลังพร็อกซีและพร็อกซีรองรับโปรโตคอลนี้ มิฉะนั้นจะช่วยให้ทุกคนสามารถหลอกที่อยู่ IP Origin |
max_post_data_size | int | 40960 | ตั้งค่าขนาดข้อมูลสูงสุดสำหรับการร้องขอโพสต์ในไบต์ |
max_put_data_size | int | 40960 | ตั้งค่าขนาดข้อมูลสูงสุดสำหรับการร้องขอในไบต์ |
max_file_descriptors | int | 524288 | จำนวนสูงสุดของตัวอธิบายไฟล์ ต้องมี threads อย่างน้อย 10 เท่า |
request_buffer_size | int | 4096 | ขอความยาวขนาดบัฟเฟอร์ หากใหญ่กว่าค่าเริ่มต้นของ 4096 จะได้รับการจัดสรรแบบไดนามิก |
allow_temp_files | str | "" | ใช้ไฟล์ชั่วคราว ตั้งค่าเป็น post สำหรับการร้องขอโพสต์ put คำขอวางหรือ all (เทียบเท่ากับการตั้งค่าเพื่อ post put ) สำหรับทั้งคู่ |
error_template | str | เทมเพลตข้อผิดพลาดเริ่มต้น | เทมเพลตสำหรับรหัสข้อผิดพลาด ดูตัวแปรด้านล่าง |
error_template| ตัวแปร | พิมพ์ | คำอธิบาย |
|---|---|---|
short_message | str | ข้อความแสดงข้อผิดพลาดสั้น ๆ (เช่น Not found ) |
long_message | str | ข้อความแสดงข้อผิดพลาดยาว (เช่น The requested resource could not be found on this server ) |
Lwan สามารถลดสิทธิ์ให้กับผู้ใช้ในระบบและ จำกัด มุมมองระบบไฟล์ด้วย chroot ในขณะที่ไม่ได้เป็นกระสุนสิ่งนี้ให้ความปลอดภัยชั้นแรกในกรณีที่มีข้อผิดพลาดใน Lwan
ในการใช้คุณสมบัตินี้ประกาศส่วน straitjacket (หรือ straightjacket ) และตั้งค่าตัวเลือกบางอย่าง สิ่งนี้ต้องการให้ Lwan ถูกดำเนินการเป็น root
แม้ว่าส่วนนี้สามารถเขียนได้ทุกที่ในไฟล์ (ตราบใดที่มันเป็นประกาศระดับสูงสุด) หากไดเรกทอรีใด ๆ เปิดอยู่เนื่องจากการสร้างอินสแตนซ์โมดูล serve_files แต่ Lwan จะปฏิเสธที่จะเริ่มต้น (การตรวจสอบนี้ดำเนินการเฉพาะใน Linux เพื่อป้องกันการกำหนดค่า malconfiguration)
เคล็ดลับ
ประกาศ straitjacket ก่อนส่วน site ในลักษณะที่ไฟล์การกำหนดค่าและข้อมูลส่วนตัว (เช่นคีย์ TLS) อยู่ไม่ไกลจากเซิร์ฟเวอร์หลังจากการเริ่มต้นเกิดขึ้น
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
user | str | NULL | ลดสิทธิ์ในชื่อผู้ใช้นี้ |
chroot | str | NULL | เส้นทางสู่ chroot() |
drop_capabilities | bool | true | ลดความสามารถทั้งหมดด้วย capset (2) (ภายใต้ linux) หรือจำนำ (2) (ภายใต้ OpenBSD) |
หากมีความจำเป็นที่จะต้องระบุส่วนหัวที่กำหนดเองสำหรับการตอบกลับแต่ละครั้งเราสามารถประกาศส่วนส่วน headers ในขอบเขตทั่วโลก ลำดับที่ส่วนนี้ปรากฏไม่สำคัญ
ตัวอย่างเช่นการประกาศนี้:
headers {
Server = Apache/1.0.0 or nginx/1.0.0 (at your option)
Some-Custom-Header = ${WITH_THIS_ENVIRONMENT_VARIABLE}
}
ทั้งคู่จะแทนที่ส่วนหัว Server ( Server: lwan จะไม่ถูกส่ง) และตั้งค่า Some-Custom-Header ด้วยค่าที่ได้จากตัวแปรสภาพแวดล้อม $WITH_THIS_ENVIRONMENT_VARIABLE
ส่วนหัวบางส่วนไม่สามารถถูกแทนที่ได้เนื่องจากอาจทำให้เกิดปัญหาเมื่อส่งค่าจริงในขณะที่ให้บริการคำขอ สิ่งเหล่านี้รวมถึง แต่ไม่ จำกัด เพียง:
DateExpiresWWW-AuthenticateConnectionContent-TypeTransfer-EncodingAccess-Control-Allow- ทั้งหมด บันทึก
ชื่อส่วนหัวยังเป็นตัวพิมพ์ใหญ่ (และการรักษากรณี) SeRVeR Overriding จะแทนที่ส่วนหัว Server แต่ส่งไปตามวิธีที่เขียนไว้ในไฟล์การกำหนดค่า
มีผู้ฟังเพียงสองคนเท่านั้นที่ได้รับการสนับสนุนต่อกระบวนการ LWAN: ผู้ฟัง HTTP (ส่วน listener ) และผู้ฟัง HTTPS (ส่วน tls_listener ) อนุญาตให้มีผู้ฟังเพียงคนเดียวของแต่ละประเภทเท่านั้น
คำเตือน
การสนับสนุน TLS เป็นการทดลอง แม้ว่ามันจะมีเสถียรภาพในระหว่างการทดสอบครั้งแรก แต่ระยะทางของคุณอาจแตกต่างกันไป รองรับ TLSV1.2 เท่านั้นที่จุดนี้ แต่มีการวางแผน TLSV1.3
บันทึก
การสนับสนุน TLS ต้องการ? Linux กับโมดูล tls.ko ในตัวหรือโหลด สนับสนุนระบบปฏิบัติการอื่น ๆ ในอนาคต ดูเหมือนว่า FreeBSD จะเป็นไปได้ระบบปฏิบัติการอื่น ๆ ดูเหมือนจะไม่เสนอคุณสมบัติที่คล้ายกัน สำหรับระบบปฏิบัติการที่ไม่ได้รับการสนับสนุนการใช้พร็อกซีเทอร์มิเนเตอร์ TLS เช่น Hitch เป็นตัวเลือกที่ดี
สำหรับทั้งส่วน listener และ tls_listener พารามิเตอร์เดียวคือที่อยู่อินเตอร์เฟสและพอร์ตที่จะฟัง ไวยากรณ์ของฟังคือ ${ADDRESS}:${PORT} โดยที่ ${ADDRESS} สามารถเป็น * (เชื่อมโยงกับอินเทอร์เฟซทั้งหมด) ที่อยู่ IPv6 (ถ้าล้อมรอบด้วยวงเล็บเหลี่ยม) ที่อยู่ IPv4 หรือชื่อโฮสต์ ตัวอย่างเช่น listener localhost:9876 จะฟังเฉพาะในอินเตอร์เฟส lo , พอร์ต 9876
ในขณะที่ส่วน listener ไม่ต้องใช้กุญแจ แต่ส่วน tls_listener ต้องการสอง: cert และ key ( hsts จุดตามลำดับไปยังตำแหน่งบนดิสก์ที่ใบรับรอง Strict-Transport-Security และไฟล์คีย์ส่วนตัวอยู่)
เคล็ดลับ
ในการสร้างคีย์เหล่านี้เพื่อวัตถุประสงค์ในการทดสอบเครื่องมือบรรทัดคำสั่ง OpenSSL สามารถใช้งานได้ดังต่อไปนี้: openssl req -nodes -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 7
บันทึก
ขอแนะนำให้ประกาศตัวเลือก straitjacket ที่มีตัวเลือก chroot ทันทีหลังจากส่วน tls_listener ในลักษณะที่เส้นทางไปยังใบรับรองและคีย์ไม่สามารถเข้าถึงได้จากจุดนั้น
หากใช้การเปิดใช้งานซ็อกเก็ต SystemD systemd สามารถระบุได้ว่าเป็นพารามิเตอร์ (หากระบุผู้ฟังหลายคนจาก SystemD systemd:FileDescriptorName ได้โดยที่ FileDescriptorName ติดตามการประชุมที่ตั้งไว้ในเอกสาร systemd.socket )
ตัวอย่าง:
listener *:8080 # Listen on all interfaces, port 8080, HTTP
tls_listener *:8081 { # Listen on all interfaces, port 8081, HTTPS
cert = /path/to/cert.pem
key = /path/to/key.pem
}
# Use named systemd socket activation for HTTP listener
listener systemd:my-service-http.socket
# Use named systemd socket activation for HTTPS listener
tls_listener systemd:my-service-https.socket {
...
}
กลุ่มส่วนของ site ซ์ของโมดูลและตัวจัดการที่จะตอบสนองต่อการร้องขอไปยังคำนำหน้า URL ที่กำหนด
ในการกำหนดเส้นทาง URL LWAN จะจับคู่คำนำหน้าทั่วไปที่ใหญ่ที่สุดจาก URI Request กับชุดคำนำหน้าที่ระบุไว้ในส่วนผู้ฟัง การร้องขอคำนำหน้าโดยเฉพาะจะได้รับการจัดการขึ้นอยู่กับว่าตัวจัดการหรือโมดูลใดได้รับการประกาศในส่วนผู้ฟัง ตัวจัดการและโมดูลมีความคล้ายคลึงกันภายใน ตัวจัดการเป็นเพียงฟังก์ชั่นและไม่มีสถานะและโมดูลถือสถานะ (ชื่ออินสแตนซ์) หลายอินสแตนซ์ของโมดูลสามารถปรากฏในส่วนผู้ฟัง
ไม่มีไวยากรณ์พิเศษในการแนบคำนำหน้าเข้ากับตัวจัดการหรือโมดูล กฎแยกวิเคราะห์การกำหนดค่าทั้งหมดใช้ที่นี่ ใช้ ${NAME} ${PREFIX} เพื่อเชื่อมโยงพา ธ คำนำหน้า ${PREFIX} ไปยังตัวจัดการชื่อ ${NAME} (ถ้า ${NAME} เริ่มต้นด้วย & เช่นเดียวกับที่อยู่ "ของผู้ให้บริการ" ของ C หรือโมดูลชื่อ ${NAME} สามารถใช้ส่วนที่ว่างเปล่าได้ที่นี่
แต่ละโมดูลจะมีชุดตัวเลือกเฉพาะและอยู่ในรายการในส่วนถัดไป นอกเหนือจากตัวเลือกการกำหนดค่าส่วน authorization พิเศษสามารถนำเสนอในการประกาศอินสแตนซ์ของโมดูล ตัวจัดการไม่ได้ใช้ตัวเลือกการกำหนดค่าใด ๆ แต่อาจรวมถึงส่วน authorization
เคล็ดลับ
การดำเนินการ LWAN ด้วยอาร์กิวเมนต์บรรทัดคำสั่ง --help จะแสดงรายการของโมดูลและตัวจัดการในตัว
ต่อไปนี้เป็นเอกสารพื้นฐานบางอย่างสำหรับโมดูลที่ส่งมาพร้อมกับ Lwan
โมดูล serve_files จะให้บริการไฟล์แบบคงที่และสร้างดัชนีไดเรกทอรีโดยอัตโนมัติหรือให้บริการไฟล์ที่บีบอัดล่วงหน้า โดยทั่วไปแล้วจะพยายามอย่างเต็มที่เพื่อให้บริการไฟล์ในวิธีที่เร็วที่สุดเท่าที่จะเป็นไปได้ตามฮิวริสติกบางอย่าง
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
path | str | NULL | เส้นทางไปยังไดเรกทอรีที่มีไฟล์ที่จะให้บริการ |
index_path | str | index.html | ชื่อไฟล์เพื่อใช้เป็นดัชนีสำหรับไดเรกทอรี |
serve_precompressed_path | bool | true | หากมี $ file.gz มีขนาดเล็กกว่าและใหม่กว่า $ ไฟล์และลูกค้ายอมรับการเข้ารหัส gzip ให้ถ่ายโอน |
auto_index | bool | true | สร้างรายการไดเรกทอรีโดยอัตโนมัติหากไม่มีไฟล์ index_path อยู่ มิฉะนั้นให้ผลตอบแทน 404 |
auto_index_readme | bool | true | รวมเนื้อหาของไฟล์ readMe เป็นส่วนหนึ่งของดัชนีไดเรกทอรีที่สร้างขึ้นโดยอัตโนมัติ |
directory_list_template | str | NULL | เส้นทางไปยังเทมเพลตหนวดสำหรับรายการไดเรกทอรี โดยค่าเริ่มต้นให้ใช้เทมเพลตภายใน |
read_ahead | int | 131702 | จำนวนไบต์สูงสุดที่จะอ่านล่วงหน้าเมื่อแคชเปิดไฟล์ ค่า 0 ปิดใช้งาน readahead ReadAhead ดำเนินการโดยเธรดลำดับความสำคัญต่ำเพื่อไม่บล็อกเธรด I/O ในขณะที่ส่วนขยายของไฟล์กำลังอ่านจากระบบไฟล์ |
cache_for | time | 5s | เวลาในการเก็บข้อมูลข้อมูลเมตาของไฟล์ (ขนาดเนื้อหาที่บีบอัด, ตัวอธิบายไฟล์เปิด ฯลฯ ) ในแคช |
บันทึก
ไฟล์ที่มีขนาดเล็กกว่า 16Kib จะถูกบีบอัดใน RAM ในช่วงเวลาที่ระบุในการตั้งค่า cache_for Lwan จะพยายามบีบอัดด้วย deflate เสมอและจะเลือกบีบอัดด้วย Brotli และ Zstd (ถ้า Lwan ถูกสร้างขึ้นด้วยการสนับสนุนที่เหมาะสม)
ในกรณีที่การบีบอัดจะไม่คุ้มค่ากับความพยายาม (เช่นการเพิ่มส่วนหัว Content-Encoding จะส่งผลให้มีการตอบสนองที่ใหญ่กว่าการส่งไฟล์ที่ไม่ได้บีบอัดโดยปกติแล้วกรณีสำหรับไฟล์ขนาดเล็กมาก) Lwan จะไม่ใช้เวลาในการบีบอัดไฟล์
สำหรับไฟล์ที่มีขนาดใหญ่กว่า 16kib Lwan จะไม่พยายามบีบอัดไฟล์เหล่านั้น ในเวอร์ชันอนาคตอาจทำเช่นนี้และส่งคำตอบโดยใช้การเข้ารหัสแบบ chunked ในขณะที่ไฟล์กำลังถูกบีบอัด (ถึงขีด จำกัด ที่แน่นอนแน่นอน) แต่สำหรับตอนนี้มีการพิจารณาเฉพาะไฟล์ที่ถูกบีบ serve_precompressed_path เท่านั้น
สำหรับทุกกรณี LWAN อาจลองใช้รุ่น GZIPPED หากพบในระบบไฟล์และไคลเอนต์ร้องขอการเข้ารหัสนี้
directory_list_template| ตัวแปร | พิมพ์ | คำอธิบาย |
|---|---|---|
rel_path | str | เส้นทางที่สัมพันธ์กับเส้นทางที่แท้จริงของไดเรกทอรีรากจริง |
readme | str | สารบัญของไฟล์ readme แรกที่พบ ( readme , readme.txt , read.me , README.TXT , README ) |
file_list | ตัววนซ้ำ | วนซ้ำในรายการไฟล์ |
file_list.zebra_class | str | odd สำหรับรายการแปลก ๆ หรือ even กระทั่งรายการ |
file_list.icon | str | พา ธ ไปยังไอคอนสำหรับประเภทไฟล์ |
file_list.name | str | ชื่อไฟล์ (หลบหนี) |
file_list.type | str | ประเภทไฟล์ (ไดเรกทอรีหรือไฟล์ปกติ) |
file_list.size | int | ขนาดไฟล์ |
file_list.unit | str | หน่วยสำหรับ file_size |
โมดูล lua จะอนุญาตให้มีการร้องขอโดยสคริปต์ที่เขียนในภาษาการเขียนโปรแกรม LUA แม้ว่าฟังก์ชั่นที่จัดทำโดยโมดูลนี้ค่อนข้างสปาร์ตัน แต่ก็สามารถเรียกใช้เฟรมเวิร์กเช่นกะลาสี
สคริปต์สามารถเสิร์ฟจากไฟล์หรือฝังอยู่ในไฟล์การกำหนดค่าและผลลัพธ์ของการโหลดโมดูล LUA มาตรฐานและ (เป็นทางเลือกถ้าใช้ Luajit) การเพิ่มประสิทธิภาพรหัสจะถูกแคชสักพัก
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
default_type | str | text/plain | ประเภท MIME เริ่มต้นสำหรับการตอบกลับ |
script_file | str | NULL | เส้นทางสู่สคริปต์ lua |
cache_period | time | 15s | เวลาที่จะเก็บสถานะของ Lua ไว้ในหน่วยความจำ |
script | str | NULL | อินไลน์สคริปต์ lua |
บันทึก
สคริปต์ Lua ไม่สามารถใช้ตัวแปรทั่วโลกได้เนื่องจากอาจไม่เพียง แต่ให้บริการโดยเธรดที่แตกต่างกัน แต่สถานะจะใช้ได้เฉพาะกับระยะเวลาที่ระบุในตัวเลือกการกำหนดค่า cache_period เท่านั้น นี่เป็นเพราะแต่ละเธรด I/O ใน LWAN จะสร้างอินสแตนซ์ของ LUA VM (เช่นโครงสร้าง lua_State หนึ่งตัวสำหรับทุกเธรด I/O) และ Lwan Coroutine แต่ละตัวจะวางไข่เธรด LUA (พร้อม lua_newthread() ) ต่อคำขอ
ไม่จำเป็นต้องมีหนึ่งอินสแตนซ์ของโมดูล LUA สำหรับแต่ละจุดสิ้นสุด สคริปต์เดียวที่ฝังอยู่ในไฟล์การกำหนดค่าหรืออย่างอื่นสามารถให้บริการจุดสิ้นสุดที่แตกต่างกันมากมาย สคริปต์ควรจะใช้ฟังก์ชั่นด้วยลายเซ็นต่อไปนี้: handle_${METHOD}_${ENDPOINT}(req) โดยที่ ${METHOD} สามารถเป็นวิธี http (เช่น get , post , head ฯลฯ ) และ ${ENDPOINT} เป็นจุดสิ้นสุดที่ต้องการ ฟังก์ชั่น handle(req) จะถูกเรียกใช้หากไม่มีเวอร์ชันเฉพาะ
เคล็ดลับ
ใช้ปลายทาง root สำหรับ catchall ตัวอย่างเช่นฟังก์ชั่น Handler handle_get_root() จะถูกเรียกใช้หากไม่พบตัวจัดการอื่นสำหรับคำขอนั้น หากไม่ได้ระบุ catchall เซิร์ฟเวอร์จะส่งคืนข้อผิดพลาด 404 Not Found
พารามิเตอร์ req ชี้ไปที่ metatable ที่มีวิธีการรับข้อมูลจากคำขอหรือเพื่อตั้งค่าการตอบกลับดังที่เห็นด้านล่าง:
req:query_param(param) ส่งคืนพารามิเตอร์การสืบค้น (จากสตริงคิวรี) ด้วย param คีย์หรือ nil หากไม่พบreq:post_param(param) ส่งคืนพารามิเตอร์โพสต์ (เฉพาะสำหรับ ${POST} handlers) พร้อม param คีย์หรือ nil หากไม่พบreq:set_response(str) ตั้งค่าการตอบสนองของสตริง strreq:say(str) ส่งคำตอบ (โดยใช้การเข้ารหัสแบบ chunked ใน HTTP)req:send_event(event, str) ส่งเหตุการณ์ (ใช้เหตุการณ์เซิร์ฟเวอร์-เซิร์ฟเวอร์)req:cookie(param) ส่งคืนคุกกี้ชื่อ param หรือ nil พบreq:set_headers(tbl) ตั้งส่วนหัวการตอบกลับจากตาราง tbl ; ส่วนหัวอาจถูกระบุหลายครั้งโดยใช้ตารางแทนที่จะเป็นสตริงในค่าตาราง ( {'foo'={'bar', 'baz'}} ); ต้องเรียกก่อนส่งคำตอบใด ๆ ด้วย say() หรือ send_event()req:header(name) ได้รับส่วนหัวจากคำขอที่มีชื่อหรือ nil ถ้าไม่พบreq:sleep(ms) หยุดตัวจัดการปัจจุบันสำหรับจำนวนมิลลิวินาทีที่กำหนดreq:ws_upgrade() ส่งคืน 1 หากการเชื่อมต่อสามารถอัปเกรดเป็น WebSocket; 0 อย่างอื่นreq:ws_write_text(str) ส่ง str ผ่านการเชื่อมต่อที่อัพเกรด WebSocket เป็นเฟรมข้อความreq:ws_write_binary(str) ส่ง str ผ่านการเชื่อมต่อที่อัปเกรด WebSocket เป็นเฟรมไบนารีreq:ws_write(str) ส่ง str ผ่านการเชื่อมต่อ WebSocket-Upgraded เป็นข้อความหรือเฟรมไบนารีขึ้นอยู่กับเนื้อหาที่มีอักขระ ASCII เท่านั้นหรือไม่req:ws_read() ส่งคืนสตริงด้วยเนื้อหาของเฟรม WebSocket ล่าสุดหรือตัวเลขที่ระบุสถานะ (enotconn/107 บน linux หากถูกตัดการเชื่อมต่อ; Eagain/11 บน linux หากไม่มี enomsg/42 บน linux เป็นอย่างอื่น) ค่าผลตอบแทนที่นี่อาจเปลี่ยนแปลงในอนาคตสำหรับสิ่งที่เหมือน Lua มากกว่าreq:remote_address() ส่งคืนสตริงด้วยที่อยู่ IP ระยะไกลreq:path() ส่งคืนสตริงด้วยเส้นทางคำขอreq:query_string() ส่งคืนสตริงด้วยสตริงการสืบค้น (สตริงว่างถ้าไม่มีสตริงคิวรีอยู่)req:body() ส่งคืนร่างกายคำขอ (โพสต์/ใส่คำขอ)req:request_id() ส่งคืนสตริงที่มีรหัสคำขอreq:request_date() ส่งคืนวันที่ตามที่จะเขียนในส่วนหัวการตอบกลับ Datereq:is_https() ส่งคืน true หากคำขอนี้ได้รับการบริการผ่าน HTTPS, false อย่างอื่นreq:host() ส่งคืนค่าของส่วนหัว Host ถ้ามีมิฉะนั้น nilreq:http_version() ส่งคืน HTTP/1.0 หรือ HTTP/1.1 ขึ้นอยู่กับเวอร์ชันคำขอreq:http_method() ส่งคืนสตริงในตัวพิมพ์ใหญ่ด้วยวิธี HTTP (เช่น "GET" )req:http_headers() ส่งคืนตารางพร้อมส่วนหัวทั้งหมดและค่าของพวกเขา ฟังก์ชั่นตัวจัดการอาจส่งคืนทั้ง nil (ซึ่งในกรณีนี้การตอบกลับ 200 OK ถูกสร้างขึ้น) หรือตัวเลขที่ตรงกับรหัสสถานะ HTTP การพยายามส่งคืนรหัสสถานะ HTTP ที่ไม่ถูกต้องหรือสิ่งอื่นใดนอกเหนือจากตัวเลขหรือ nil จะส่งผลให้เกิดการตอบสนอง 500 Internal Server Error
นอกเหนือจาก metamethods ในพารามิเตอร์ req แล้วเรายังสามารถบันทึกข้อความด้วยระดับการบันทึกที่แตกต่างกันโดยวิธีการเรียกใช้จาก Lwan.log :
Lwan.log:warning(str)Lwan.log:info(str)Lwan.log:error(str)Lwan.log:critical(str) (จะยกเลิก Lwan! ใช้ด้วยความระมัดระวัง)Lwan.log:debug(str) (มีเฉพาะใน builds debug; no-op เป็นอย่างอื่น) บันทึก
หาก Lwan ถูกสร้างขึ้นด้วยการสนับสนุน syslog ข้อความเหล่านี้จะถูกส่งไปยังบันทึกระบบมิฉะนั้นพวกเขาจะถูกพิมพ์ไปยังข้อผิดพลาดมาตรฐาน
โมดูล rewrite จะจับคู่รูปแบบใน URL และให้ตัวเลือกในการเปลี่ยนเส้นทางไปยัง URL อื่นหรือเขียนคำขอใหม่ในลักษณะที่ Lwan จะจัดการกับคำขอราวกับว่ามันถูกสร้างขึ้นมาในตอนแรก
บันทึก
จาก Lua 5.3.1 เครื่องยนต์ expresion ปกติอาจไม่ได้รับการบรรจุคุณสมบัติเป็นเครื่องยนต์อเนกประสงค์ทั่วไปส่วนใหญ่ แต่ได้รับการคัดเลือกโดยเฉพาะเพราะมันเป็นออโตเมติก จำกัด ที่กำหนดไว้ในความพยายามที่จะทำการปฏิเสธการโจมตีบริการบางอย่างที่เป็นไปไม่ได้
URL ใหม่สามารถระบุได้โดยใช้ไวยากรณ์การแทนที่ข้อความอย่างง่ายหรือใช้สคริปต์ LUA
เคล็ดลับ
สคริปต์ Lua จะมี metamethods เดียวกันที่มีอยู่ใน req metatable ที่จัดทำโดยโมดูล Lua ดังนั้นจึงมีประสิทธิภาพค่อนข้างมาก
แต่ละอินสแตนซ์ของโมดูลการเขียนซ้ำจะต้องใช้ pattern และการกระทำเพื่อดำเนินการเมื่อรูปแบบดังกล่าวจับคู่ รูปแบบจะถูกประเมินตามลำดับที่ปรากฏในไฟล์การกำหนดค่าและมีการระบุโดยใช้ส่วนซ้อนในไฟล์การกำหนดค่า ตัวอย่างเช่นพิจารณาตัวอย่างต่อไปนี้โดยระบุรูปแบบสองรูปแบบ:
rewrite /some/base/endpoint {
pattern posts/(%d+) {
# Matches /some/base/endpointposts/2600 and /some/base/endpoint/posts/2600
rewrite_as = /cms/view-post?id=%1
}
pattern imgur/(%a+)/(%g+) {
# Matches /some/base/endpointimgur/gif/mpT94Ld and /some/base/endpoint/imgur/gif/mpT94Ld
redirect_to = https://i.imgur.com/%2.%1
}
}
ตัวอย่างนี้กำหนดสองรูปแบบหนึ่งที่ให้ URL ที่ดีกว่าที่ซ่อนอยู่จากผู้ใช้และอีกรูปแบบหนึ่งที่ให้วิธีที่แตกต่างกันในการรับลิงก์โดยตรงไปยังรูปภาพที่โฮสต์บนบริการโฮสติ้งรูปภาพยอดนิยม (เช่นการร้องขอ /some/base/endpoint/imgur/mp4/4kOZNYX
ค่าของ rewrite_as หรือ redirect_to สามารถเป็นสคริปต์ lua ได้เช่นกัน; ในกรณีนี้ตัวเลือก expand_with_lua จะต้องตั้งค่าเป็น true และแทนที่จะใช้ไวยากรณ์การทดแทนข้อความอย่างง่ายเป็นตัวอย่างด้านบนฟังก์ชันที่ชื่อ handle_rewrite(req, captures) จะต้องกำหนดแทน พารามิเตอร์ req ถูกบันทึกไว้ในส่วนโมดูล LUA; พารามิเตอร์ captures คือตารางที่มีการจับทั้งหมดตามลำดับ (เช่น captures[2] เทียบเท่ากับ %2 ในไวยากรณ์การทดแทนข้อความอย่างง่าย) ฟังก์ชั่นนี้ส่งคืน URL ใหม่เพื่อเปลี่ยนเส้นทางไป
โมดูลนี้ไม่มีตัวเลือกด้วยตัวเอง มีการระบุตัวเลือกในแต่ละรูปแบบ
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
rewrite_as | str | NULL | เขียน url ใหม่ตามรูปแบบนี้ |
redirect_to | str | NULL | เปลี่ยนเส้นทางไปยัง URL ใหม่ตามรูปแบบนี้ |
expand_with_lua | bool | false | ใช้สคริปต์ Lua เพื่อเปลี่ยนเส้นทางหรือเขียนคำขอใหม่ |
ตัวเลือก redirect_to และ rewrite_as เป็นแบบพิเศษร่วมกันและหนึ่งในนั้นจะต้องระบุอย่างน้อย
นอกจากนี้ยังเป็นไปได้ที่จะระบุเงื่อนไขเพื่อทริกเกอร์การเขียนใหม่ หากต้องการระบุหนึ่งให้เปิดบล็อก condition ให้ระบุประเภทเงื่อนไขจากนั้นพารามิเตอร์สำหรับเงื่อนไขนั้นที่จะประเมิน สามารถตั้งค่าหลายเงื่อนไขต่อกฎการเขียนซ้ำตราบเท่าที่มีหนึ่งเงื่อนไขต่อประเภท:
| เงื่อนไข | สามารถใช้สาร ไวยากรณ์ | ส่วนที่ต้องการ | พารามิเตอร์ | คำอธิบาย |
|---|---|---|---|---|
cookie | ใช่ | ใช่ | key เดียว = value | ตรวจสอบว่าคำขอมี key คุกกี้มี value |
query | ใช่ | ใช่ | key เดียว = value | ตรวจสอบว่าคำขอมีคีย์ key แบบสอบถามมี value |
post | ใช่ | ใช่ | key เดียว = value | ตรวจสอบว่าคำขอมี key ข้อมูลโพสต์มี value |
header | ใช่ | ใช่ | key เดียว = value | ตรวจสอบว่า key ส่วนหัวคำขอมี value หรือไม่ |
environment | ใช่ | ใช่ | key เดียว = value | ตรวจสอบว่า key ตัวแปรสภาพแวดล้อมมี value |
stat | ใช่ | ใช่ | path , is_dir , is_file | ตรวจสอบว่า path อยู่ในระบบไฟล์หรือไม่และเลือกตรวจสอบว่า is_dir หรือ is_file |
encoding | เลขที่ | ใช่ | deflate , gzip , brotli , zstd , none | ตรวจสอบว่าลูกค้ายอมรับคำตอบในการเข้ารหัสที่กำหนด (เช่น deflate = yes สำหรับการเข้ารหัส deflate) |
proxied | เลขที่ | เลขที่ | บูลีน | ตรวจสอบว่าคำขอได้รับการส่งมอบพร็อกซีผ่านโปรโตคอลพร็อกซี |
http_1.0 | เลขที่ | เลขที่ | บูลีน | ตรวจสอบว่ามีการร้องขอด้วยไคลเอนต์ HTTP/1.0 |
is_https | เลขที่ | เลขที่ | บูลีน | ตรวจสอบว่ามีการร้องขอผ่าน https |
has_query_string | เลขที่ | เลขที่ | บูลีน | ตรวจสอบว่าคำขอมีสตริงแบบสอบถาม (แม้ว่าจะว่าง) |
method | เลขที่ | เลขที่ | ชื่อวิธี | ตรวจสอบว่าวิธี HTTP เป็นวิธีที่ระบุหรือไม่ |
lua | เลขที่ | เลขที่ | สาย | เรียกใช้ฟังก์ชั่น lua matches(req) ภายในสตริงและตรวจสอบว่ามันส่งคืน true หรือ false |
backref | เลขที่ | ใช่ | backref index เดียว = value | ตรวจสอบว่าหมายเลข backref ตรงกับค่าที่ให้ไว้หรือไม่ |
สามารถใช้สาร ไวยากรณ์ หมายถึงความสามารถในการอ้างอิงรูปแบบที่ตรงกันโดยใช้ไวยากรณ์การทดแทนแบบเดียวกับที่ใช้สำหรับ rewrite as หรือ redirect to การกระทำ ตัวอย่างเช่น condition cookie { some-cookie-name = foo-%1-bar } จะแทนที่ %1 ด้วยการจับคู่แรกจากรูปแบบเงื่อนไขนี้เกี่ยวข้องกับ
บันทึก
เงื่อนไขที่ไม่ต้องการส่วนจะต้องเขียนเป็นกุญแจ ตัวอย่างเช่น condition has_query_string = yes
ตัวอย่างเช่นหากต้องการส่ง site-dark-mode.css หากมีคุกกี้ style ที่มีค่า dark และส่ง site-light-mode.css เป็นอย่างอื่นเราสามารถเขียนได้:
pattern site.css {
rewrite as = /site-dark-mode.css
condition cookie { style = dark }
}
pattern site.css {
rewrite as = /site-light-mode.css
}
อีกตัวอย่างหนึ่ง: หากต้องการส่งไฟล์ที่บีบอัดไว้ล่วงหน้าหากมีอยู่ในระบบไฟล์และผู้ใช้ร้องขอ:
pattern (%g+) {
condition encoding { brotli = yes }
condition stat { path = %1.brotli }
rewrite as = %1.brotli
}
pattern (%g+) {
condition encoding { gzip = yes }
condition stat { path = %1.gzip }
rewrite as = %1.gzip
}
pattern (%g+) {
condition encoding { zstd = yes }
condition stat { path = %1.zstd }
rewrite as = %1.zstd
}
pattern (%g+) {
condition encoding { deflate = yes }
condition stat { path = %1.deflate }
rewrite as = %1.deflate
}
บันทึก
โดยทั่วไปแล้วสิ่งนี้ไม่จำเป็นเนื่องจากโมดูลการให้บริการไฟล์จะทำสิ่งนี้โดยอัตโนมัติและเลือกไฟล์ที่เล็กที่สุดที่มีสำหรับการเข้ารหัสที่ร้องขอ แต่สิ่งนี้แสดงให้เห็นว่ามันเป็นไปได้ที่จะมีคุณสมบัติที่คล้ายกันโดยการกำหนดค่าเพียงอย่างเดียว
โมดูล redirect จะดังที่ระบุไว้ในกระป๋องสร้าง 301 Moved permanently (โดยค่าเริ่มต้นรหัสสามารถเปลี่ยนแปลงได้ดูด้านล่าง) การตอบสนอง) ตามตัวเลือกที่ระบุไว้ในการกำหนดค่า โดยทั่วไปควรใช้โมดูล rewrite แทนเนื่องจากมีคุณสมบัติมากขึ้น อย่างไรก็ตามโมดูลนี้ทำหน้าที่เป็นตัวอย่างของวิธีการเขียนโมดูล LWAN (น้อยกว่า 100 บรรทัดของรหัส)
หากไม่ได้ระบุตัวเลือก to จะสร้างการตอบกลับ 500 Internal Server Error เสมอ การระบุรหัส HTTP ที่ไม่ถูกต้องหรือรหัสที่ LWAN ไม่ทราบ (ดู enum lwan_http_status ) จะสร้างการตอบ 301 Moved Permanently
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
to | str | NULL | ตำแหน่งที่จะเปลี่ยนเส้นทางไปยัง |
code | int | 301 | รหัส HTTP เพื่อดำเนินการเปลี่ยนเส้นทาง |
โมดูล response จะสร้างการตอบสนองเทียมของรหัส HTTP ใด ๆ นอกเหนือจากการทำหน้าที่เป็นตัวอย่างของวิธีการเขียนโมดูล LWAN แล้วยังสามารถใช้ในการแกะสลักช่องว่างจากโมดูลอื่น ๆ (เช่นการสร้าง 405 Not Allowed ให้ตอบสนองสำหรับไฟล์ใน /.git , ถ้า / เสิร์ฟพร้อมโมดูล serve_files )
หาก code ที่ให้มาอยู่นอกรหัสการตอบกลับที่รู้จักกันโดย LWAN จะมีการส่งข้อผิดพลาด 404 Not Found แทน
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
code | int | 999 | รหัสตอบกลับ http |
พร็อกซีโมดูล fastcgi ร้องขอระหว่างไคลเอนต์ HTTP ที่เชื่อมต่อกับ LWAN และเซิร์ฟเวอร์ FASTCGI ที่สามารถเข้าถึงได้โดย LWAN สิ่งนี้มีประโยชน์เช่นการให้บริการหน้าจากภาษาสคริปต์เช่น PHP
บันทึก
นี่เป็นรุ่นเบื้องต้นของโมดูลนี้และเช่นนี้ไม่ได้รับการปรับปรุงอย่างดีคุณสมบัติบางอย่างขาดหายไปและค่าบางอย่างที่มีให้กับสภาพแวดล้อมที่ได้รับการเข้ารหัส
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
address | str | ที่อยู่เพื่อเชื่อมต่อกับ สามารถเป็นพา ธ ไฟล์ (สำหรับซ็อกเก็ตโดเมน Unix), ที่อยู่ IPv4 ( aaa.bbb.ccc.ddd:port ) หรือที่อยู่ IPv6 ( [...]:port ) | |
script_path | str | สถานที่ตั้งที่สคริปต์ CGI ตั้งอยู่ | |
default_index | str | index.php | สคริปต์เริ่มต้นเพื่อดำเนินการหากไม่ระบุใน URI Request |
ส่วนการอนุญาตสามารถประกาศในอินสแตนซ์หรือตัวจัดการโมดูลใด ๆ และให้วิธีการอนุญาตให้ปฏิบัติตามคำขอนั้นผ่านกลไกการอนุญาต HTTP มาตรฐาน เพื่อที่จะต้องได้รับอนุญาตให้เข้าถึงอินสแตนซ์หรือตัวจัดการโมดูลที่แน่นอนประกาศส่วน authorization ด้วยพารามิเตอร์ basic และตั้งหนึ่งในตัวเลือกของมัน
| ตัวเลือก | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
realm | str | Lwan | อาณาจักรสำหรับการอนุญาต โดยปกติจะแสดงใน UI ผู้ใช้/รหัสผ่านในเบราว์เซอร์ |
password_file | str | NULL | พา ธ สำหรับไฟล์ที่มีชื่อผู้ใช้และรหัสผ่าน (ในข้อความที่ชัดเจน) รูปแบบไฟล์เหมือนกับรูปแบบไฟล์การกำหนดค่าที่ใช้โดย LWAN |
คำเตือน
ไม่เพียง แต่รหัสผ่านจะถูกเก็บไว้ในข้อความที่ชัดเจนในไฟล์ที่เซิร์ฟเวอร์ควรเข้าถึงได้เท่านั้น หลีกเลี่ยงการใช้คุณสมบัตินี้หากเป็นไปได้
โปรดอ่านส่วนนี้ (และติดตาม) หากคุณวางแผนที่จะมีส่วนร่วมใน Lwan ที่นี่ไม่มีอะไรคาดคิด สิ่งนี้ส่วนใหญ่เป็นไปตามกฎและความคาดหวังของโครงการ FOSS อื่น ๆ อีกมากมาย แต่ทุกคนคาดหวังสิ่งต่าง ๆ ที่แตกต่างจากกันเล็กน้อย
Lwan พยายามทำตามรูปแบบการเข้ารหัสที่สอดคล้องกันตลอดทั้งโครงการ หากคุณกำลังพิจารณาที่จะมีส่วนร่วมในการแก้ไขโครงการโปรดเคารพสไตล์นี้โดยพยายามจับคู่สไตล์ของรหัสโดยรอบ โดยทั่วไป:
global_variables_are_named_like_this แม้ว่าพวกเขาจะหายากและควรถูกทำเครื่องหมายว่าเป็น static (มีข้อยกเว้นที่หายาก)local_var , i , conntypedef สำหรับ structs ไม่ค่อยใช้ใน lwan#pragma once แทนที่จะเป็นแฮ็กเกอร์ Guard ตามปกติlwan-private.hlwan_lwan_lwan_/* Old C-style comments are preferred */clang-format can be used to format the source code in an acceptable way; a .clang-format file is provided If modifying well-tested areas of the code (eg the event loop, HTTP parser, etc.), please add a new integration test and make sure that, before you send a pull request, all tests (including the new ones you've sent) are working. Tests can be added by modifying src/scripts/testsuite.py , and executed by either invoking that script directly from the source root, or executing the testsuite build target.
Some tests will only work on Linux, and won't be executed on other platforms.
Lwan is automatically fuzz-tested by OSS-Fuzz. To fuzz-test locally, though, one can follow the instructions to test locally.
Currently, there are fuzzing drivers for the request parsing code, the configuration file parser, the template parser, and the Lua string pattern matching library used in the rewrite module.
Adding new fuzzers is trivial:
src/bin/fuzz .${FUZZER_NAME}_fuzzer.cc . Look at the OSS-Fuzz documentation and other fuzzers on information about how to write these.src/fuzz/corpus . Files have to be named corpus-${FUZZER_NAME}-${UNIQUE_ID} . The shared object version of liblwan on ELF targets (eg Linux) will use a symbol filter script to hide symbols that are considered private to the library. Please edit src/lib/liblwan.sym to add new symbols that should be exported to liblwan.so .
Lwan tries to maintain a source history that's as flat as possible, devoid of merge commits. This means that pull requests should be rebased on top of the current master before they can be merged; sometimes this can be done automatically by the GitHub interface, sometimes they need some manual work to fix conflicts. It is appreciated if the contributor fixes these conflicts when asked.
It is advisable to push your changes to your fork on a branch-per-pull request, rather than pushing to the master branch; the reason is explained below.
Please ensure that Git is configured properly with your name (it doesn't really matter if it is your legal name or a nickname, but it should be enough to credit you) and a valid email address. There's no need to add Signed-off-by lines, even though it's fine to send commits with them.
If a change is requested in a pull request, you have two choices:
It is not enforced, but it is recommended to create smaller commits. How commits are split in Lwan is pretty much arbitrary, so please take a look at the commit history to get an idea on how the division should be made. Git offers a plethora of commands to achieve this result: the already mentioned interactive rebase, the -p option to git add , and git commit --amend are good examples.
Commit messages should have one line of summary (~72 chars), followed by an empty line, followed by paragraphs of 80-char lines explaining the change. The paragraphs explaining the changes are usually not necessary if the summary is good enough. Try to write good commit messages.
Lwan is licensed under the GNU General Public License, version 2, or (at your option), any later version. ดังนั้น:
While Lwan was written originally for Linux, it has been ported to BSD systems as well. The build system will detect the supported features and build support library functions as appropriate.
For instance, epoll has been implemented on top of kqueue, and Linux-only syscalls and GNU extensions have been implemented for the supported systems. This blog post explains the details and how #include_next is used.
It can achieve good performance, yielding about 320000 requests/second on a Core i7 laptop for requests without disk access, and without pipelining.
When disk I/O is required, for files up to 16KiB, it yields about 290000 requests/second ; for larger files, this drops to 185000 requests/second , which isn't too shabby either.
These results, of course, with keep-alive connections, and with weighttp running on the same machine (and thus using resources that could be used for the webserver itself).
Without keep-alive, these numbers drop around 6-fold.
There is an IRC channel ( #lwan ) on Libera. A standard IRC client can be used.
Here's a non-definitive list of third-party stuff that uses Lwan and have been seen in the wild. If you see mentions of Lwan in the media or academia, however small it might be, please contact the author! It'll make her day!
Some other distribution channels were made available as well:
Dockerfile is maintained by @jaxgeller, and is available from the Docker registry.Lwan has been also used as a benchmark:
Mentions in academic journals:
Mentions in magazines:
Mentions in books:
Some talks mentioning Lwan:
Not really third-party, but alas:
Lwan container images are available at ghcr.io/lpereira/lwan. Container runtimes like Docker or Podman may be used to build and run Lwan in a container.
Container images are tagged with release version numbers, so a specific version of Lwan can be pulled.
# latest version
docker pull ghcr.io/lpereira/lwan:latest
# pull a specific version
docker pull ghcr.io/lpereira/lwan:v0.3
Clone the repository and use Containerfile (Dockerfile) to build Lwan with all optional dependencies enabled.
podman build -t lwan .
The image expects to find static content at /wwwroot , so a volume containing your content can be mounted.
docker run --rm -p 8080:8080 -v ./www:/wwwroot lwan
To bring your own lwan.conf , simply mount it at /lwan.conf .
podman run --rm -p 8080:8080 -v ./lwan.conf:/lwan.conf lwan
Podman supports socket activation of containers. This example shows how to run lwan with socket activation and Podman on a Linux host.
Requirements: Podman version 4.5.0 or higher.
sudo useradd test
sudo machinectl shell test@
podman build -t lwan ~/lwan
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/systemd/user
listener systemd:my.socket
site {
serve_files / {
path = /web
}
}
[Socket]
ListenStream=8080
[Unit]
After=my.socket
Requires=my.socket
[Container]
Network=none
Image=localhost/lwan
Volume=/home/test/lwan.conf:/lwan.conf:Z
Volume=/home/test/web:/web:Z
:Z is needed on SELinux systems. As lwan only needs to communicate over the socket-activated socket, it's possible to use Network=none . See the article How to limit container privilege with socket activation. mkdir ~/web
echo hello > ~/web/file.txt
systemctl --user daemon-reload
systemctl --user start my.socket
$ curl localhost:8080/file.txt
hello
These are some of the quotes found in the wild about Lwan. They're presented in no particular order. Contributions are appreciated:
"Lwan is like a classic, according to the definition given by Italian -- writer Italo Calvino: you can read it again and again" Antonio Piccolboni
"I read lwan's source code. Especially, the part of using coroutine was very impressive and it was more interesting than a good novel. Thank you for that." -- @patagonia
"For the server side, we're using Lwan, which can handle 100k+ reqs/s. It's supposed to be super robust and it's working well for us." -- @fawadkhaliq
"Insane C thing" -- Michael Sproul
"The best performer is LWAN, a newcomer" -- InfoQ
"I've never had a chance to thank you for Lwan. It inspired me a lot to develop Zewo" -- @paulofariarl
"Let me say that lwan is a thing of beauty. I got sucked into reading the source code for pure entertainment, it's so good. high five " -- @kwilczynski
"mad science" -- jwz
"Nice work with Lwan! I haven't looked that carefully yet but so far I like what I saw. You definitely have the right ideas." -- @thinkingfish
"Lwan is a work of art. Every time I read through it, I am almost always awe-struck." -- @neurodrone
"For Round 10, Lwan has taken the crown" -- TechEmpower
"Jeez this is amazing. Just end to end, rock solid engineering. (...) But that sells this work short." kjeetgill
"I am only a spare time C coder myself and was surprised that I can follow the code. Nice!" cntlzw
"Impressive all and all, even more for being written in (grokkable!) C. Nice work." tpaschalis
"LWAN was a complete failure" dermetfan