Skip to content

Latest commit

ย 

History

281 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

BookOasis (๋ถ ์˜ค์•„์‹œ์Šค)

No Build Vanilla JS No Framework Native Python Zero Dependencies AGPLv3

English Version (README_EN.md)

๋ถ ์˜ค์•„์‹œ์Šค๋Š” ZIP/CBZ ์••์ถ• ํŒŒ์ผ ํ˜•ํƒœ์˜ ๋„์„œ ๋ฐ ๋งŒํ™”์ฑ…์„ ์›น ํ™˜๊ฒฝ์—์„œ ์ง€์—ฐ ์—†์ด ๊ฐ์ƒํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋œ ์ดˆ๊ฒฝ๋Ÿ‰, ๊ณ ์„ฑ๋Šฅ ๊ฐœ์ธ ๋ฏธ๋””์–ด ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.

์„œ๋“œํŒŒํ‹ฐ ์ข…์†์„ฑ์„ ๊ทน๋„๋กœ ์ตœ์†Œํ™”ํ•˜๊ณ  ํŒŒ์ด์ฌ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ž ์žฌ๋ ฅ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๊ตฌ๋™ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


์ฃผ์š” ํŠน์ง•

  • ํŒŒ์ผ ๋ฌดํ•ด์ œ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ

    • ๋Œ€์šฉ๋Ÿ‰ ์••์ถ• ํŒŒ์ผ(ZIP/CBZ)์„ ์„œ๋ฒ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋ฏธ๋ฆฌ ์••์ถ• ํ•ด์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ๋‚ด์žฅ zipfile ๋ชจ๋“ˆ์„ ์ œ์–ดํ•˜์—ฌ ํ•„์š”ํ•œ ํŽ˜์ด์ง€์˜ ๋ฌผ๋ฆฌ์  ๋ฐ”์ดํŠธ ์‹œ์ž‘ ์˜คํ”„์…‹๋งŒ ์ฝ์–ด ์ŠคํŠธ๋ฆฌ๋ฐ ์ „์†กํ•˜๋ฏ€๋กœ ๋””์Šคํฌ I/O์™€ CPU ์†Œ๋ชจ๋ฅผ ํ˜์‹ ์ ์œผ๋กœ ์ ˆ๊ฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฏธ๋‹ˆ๋ฉ€ํ•œ ์ข…์†์„ฑ

    • Flask ํ”„๋ ˆ์ž„์›Œํฌ ์™ธ์— ๋ฌด๊ฑฐ์šด ORM์ด๋‚˜ ์„œ๋“œํŒŒํ‹ฐ ๋ชจ๋“ˆ์„ ๋ฐฐ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ๋‚ด์žฅ SQLite ๋ชจ๋“ˆ์— ๊ณ ์„ฑ๋Šฅ ์ปค๋„ฅ์…˜ ํ’€๋ง๊ณผ ์ •๋ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์ž…ํ˜€ ์„ฑ๋Šฅ ์ €ํ•˜ ์—†๋Š” ์ดˆ๊ฒฝ๋Ÿ‰ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‹คํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ตœ์ ํ™”๋œ ํ”„๋ก ํŠธ์—”๋“œ ํŒŒ์ดํ”„๋ผ์ธ

    • ๋ทฐํฌํŠธ ๋‚ด ์นด๋“œ๋งŒ ๋กœ๋“œํ•˜๋Š” ์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading) ๋ฐ ๋‹ค์Œ ํŽ˜์ด์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ(Preloading)์„ ์ง€์›ํ•˜์—ฌ ๋Š๊น€ ์—†๋Š” ๋…์„œ ๊ฒฝํ—˜์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ์—ฐํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ

    • ํ”Œ๋Ÿฌ๊ทธ์ธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋‚ด์žฅํ•˜์—ฌ ๊ตญ๋‚ด ํ™˜๊ฒฝ์— ํŠนํ™”๋œ ์•Œ๋ผ๋”˜ Open API ๋“ฑ์˜ ์™ธ๋ถ€ ์ •๋ณด ์ˆ˜๊ธ‰ ์ฑ„๋„์„ ํ”Œ๋Ÿฌ๊ทธ์ธ ํ˜•ํƒœ๋กœ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.
    • ์ฑ… ์†Œ๊ฐœ๊ธ€, ์ž‘๊ฐ€ ์ •๋ณด, ๊ณ ํ™”์งˆ ์ปค๋ฒ„๋ฅผ ์›ํด๋ฆญ์œผ๋กœ ํ†ตํ•ฉ ๋ฐ˜์˜ํ•˜๋ฉฐ ์ˆ˜๋™ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽธ์ง‘๊ธฐ ๋ฐ ํ‘œ์ง€ ๊ต์ฒด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋ฐ”์ผ ๋ทฐ์–ด ํ˜ธํ™˜

    • ์™ธ๋ถ€ ๋ทฐ์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—ฐ๋™์„ ์œ„ํ•œ OPDS ๊ทœ๊ฒฉ์„ ์ง€์›ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธ์ฆ์ •๋ณด ๊ธฐ๋ฐ˜์˜ Basic Authentication ๋ณด์•ˆ ์ฒ˜๋ฆฌ๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์œ ์—ฐํ•œ ์Šค์บ” ์˜ˆ์™ธ ํ•„ํ„ฐ๋ง (.bookoasisignore)

    • ์‹œ๋†€๋กœ์ง€ NAS ์ธ๋„ค์ผ ํด๋”(@eaDir/), ํœด์ง€ํ†ต(#recycle/), ์ž„์‹œ ํŒŒ์ผ(*.tmp, *.sample.cbz) ๋“ฑ ์˜ˆ์™ธ ํŒจํ„ด์„ ์ „์—ญ ์„ค์ • ๋˜๋Š” ํด๋”๋ณ„ .bookoasisignore ํŒŒ์ผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์Šค์บ” ๋ฐ ๋””์Šคํฌ ํƒ์ƒ‰ ์†Œ๋ชจ๋ฅผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽจ 4์ปท ๋งŒํ™”๋กœ ๋ณด๋Š” BookOasis ๊ตฌ๋™ ์›๋ฆฌ

BookOasis๊ฐ€ ๋Œ€์šฉ๋Ÿ‰(10๋งŒ ๊ถŒ ์ด์ƒ) ํ™˜๊ฒฝ์—์„œ๋„ ๋ฒ„๋ฒ…์ž„ ์—†์ด ์ดˆ๊ด‘์†์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๋น„๋ฐ€์ž…๋‹ˆ๋‹ค!

BookOasis ๊ตฌ๋™ ์›๋ฆฌ

  • ์ดˆ๊ณ ์† ์Šค์บ๋„ˆ: ๋„์„œ์˜ ์••์ถ•ํŒŒ์ผ์„ ํ•ด์ œํ•˜์ง€ ์•Š๊ณ  ์ตœ์†Œ ์˜คํ”„์…‹๋งŒ ์ฝ์–ด ์ˆœ์‹๊ฐ„์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•ด DB์— ์‹œ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ง€์—ฐ(Lazy) ์Šค์บ๋„ˆ: ์šฉ๋Ÿ‰์ด ํฐ ๋งŒํ™”์ฑ… ZIP ํŒŒ์ผ ๋“ฑ์€ ๋ฌด๋ฆฌํ•˜๊ฒŒ ์ฆ‰์‹œ ํŒŒ์‹ฑํ•˜์ง€ ์•Š๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋‚˜๋ฅธํ•˜๊ฒŒ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฉ”์ธ ๋™์ž‘์˜ ๋ ‰์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

๋Œ€์‹œ๋ณด๋“œ ํ™”๋ฉด

BookOasis Dashboard


์‹œ์ž‘ํ•˜๊ธฐ

์ƒ์„ธํ•œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ ๋ฐ ์„ค์น˜ ๋ฐฉ๋ฒ•์€ ๊ธฐ์ˆ  ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ด๋ฒคํŠธ ์›นํ›…(book.new, book.read, book.finish)์€ ํฌ๋งท๋ณ„ ์ง„ํ–‰๋ฅ  ์ œ์•ฝ์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. EPUB/TXT๋Š” ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๊ฐ€ ๊ณ ์ •๋˜์ง€ ์•Š์•„ totalPages๊ฐ€ null์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ˆ˜์‹  ์ธก์—์„œ๋Š” progress(0~100)๋ฅผ ์šฐ์„  ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„ํŽธ ๊ตฌ๋™ (Docker)

  1. ์„ค์ • ํ…œํ”Œ๋ฆฟ ๋ณต์‚ฌ ๋กœ์ปฌ ํ™˜๊ฒฝ ๊ณ ์œ  ์„ค์ •์„ ์œ„ํ•ด ์ œ๊ณต๋˜๋Š” ์˜ค๋ฒ„๋ผ์ด๋“œ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    cp docker-compose.override.example.yml docker-compose.override.yml
  2. ๋ณผ๋ฅจ ๊ฒฝ๋กœ ์ˆ˜์ • ์ƒ์„ฑ๋œ docker-compose.override.yml ํŒŒ์ผ์„ ์—ด์–ด ๋ณธ์ธ์˜ ์‹ค์ œ ์ฑ…/๋งŒํ™”์ฑ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

    services:
      bookoasis:
        volumes:
          - /์‹ค์ œ/์ฑ…/์ €์žฅ/๊ฒฝ๋กœ:/data/comics:ro
  3. ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰

    docker compose up -d

    ๊ธฐ๋ณธ docker-compose.yml์€ ๋กœ์ปฌ ๋นŒ๋“œ ์—†์ด GHCR(ghcr.io/leeyj/bookoasis:stable)์— ๋ฏธ๋ฆฌ ๋นŒ๋“œ๋˜์–ด ๋ฐฐํฌ๋œ ๊ณต์‹ ์ด๋ฏธ์ง€๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค. Synology/Unraid ๋“ฑ ์ €์‚ฌ์–‘ NAS์—์„œ๋„ ๋น ๋ฅด๊ฒŒ ๊ธฐ๋™๋ฉ๋‹ˆ๋‹ค.

Tip: docker-compose.override.yml์€ .gitignore์— ๋“ฑ๋ก๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ํ–ฅํ›„ ํ”„๋กœ์ ํŠธ ์†Œ์Šค๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์–ด git pull์„ ๋ฐ›์•„๋„ ์‚ฌ์šฉ์ž์˜ ๊ฐœ์ธ ๊ฒฝ๋กœ ์„ค์ • ํŒŒ์ผ์ด ์ถฉ๋Œ์„ ์ผ์œผํ‚ค๊ฑฐ๋‚˜ ์œ ์‹ค๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์†Œ์Šค๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด: ๋กœ์ปฌ Dockerfile์„ ๋นŒ๋“œํ•ด์„œ ์“ฐ๋Š” docker-compose.build.yml์„ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์„ธ์š”.

docker compose -f docker-compose.build.yml -f docker-compose.override.yml up -d --build

๋ณด์•ˆ ์ •์ฑ…์— ๋”ฐ๋ผ ์šด์˜์ž์šฉ ๋ฐฐํฌ/์—…๋ฐ์ดํŠธ ์ ˆ์ฐจ๋Š” ๋น„๊ณต๊ฐœ ๋‚ด๋ถ€ ๋ฌธ์„œ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ง์ ‘ ๊ตฌ๋™ (Native Python)

๐Ÿง Linux / macOS ํ™˜๊ฒฝ

# ๊ฐ€์ƒํ™˜๊ฒฝ ํ™œ์„ฑํ™” ๋ฐ ์ข…์†์„ฑ ์„ค์น˜
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# ์„ค์ • ํŒŒ์ผ ๊ตฌ์„ฑ
# .env ๋‚ด SECRET_KEY ํ•ญ๋ชฉ์— ์ž์‹ ๋งŒ์˜ ์ž„์˜์˜ ๊ธด ๋ฌธ์ž์—ด์„ ์ž…๋ ฅํ•˜์—ฌ ๋ณด์•ˆ ๊ณ ์ • ํ‚ค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
# ์ด ํ‚ค๋ฅผ ๊ณ ์ •ํ•ด ์ฃผ์‹œ๋ฉด ์„œ๋ฒ„ ๊ธฐ๋™ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์žฌ์‹œ์ž‘๋˜๋”๋ผ๋„ ์‚ฌ์šฉ์ž ์„ธ์…˜(๋กœ๊ทธ์ธ ์ƒํƒœ)์ด ํ’€๋ฆฌ์ง€ ์•Š๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

# ์„œ๋ฒ„ ๊ธฐ๋™
python core.py
  • ๊ธฐ๋ณธ ๋™์ž‘: ๋„์ปค ์™ธ ํ™˜๊ฒฝ์—์„œ๋Š” ์Šค์บ๋„ˆ ์›Œ์ปค๊ฐ€ ์ž๋™์œผ๋กœ ํ•จ๊ป˜ ๊ธฐ๋™๋˜์–ด ํ ๋Œ€๊ธฐ์—ด(pending)์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„์š” ์‹œ ๋น„ํ™œ์„ฑํ™”: BOOKOASIS_ENABLE_EMBEDDED_WORKER=0 python core.py

๐ŸชŸ Windows ํ™˜๊ฒฝ

์œˆ๋„์šฐ ํ™˜๊ฒฝ์—์„œ๋Š” ๋งˆ์šฐ์Šค ๋”๋ธ”ํด๋ฆญ ํ•œ ๋ฒˆ์œผ๋กœ ๊ตฌ๋™ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ ๋ฐ ํŒจํ‚ค์ง€ ์„ค์น˜๋ถ€ํ„ฐ ํ”„๋กœ๋•์…˜ ์ˆ˜์ค€์˜ ์›น ์„œ๋ฒ„(waitress) ์‹คํ–‰๊นŒ์ง€ ์ž๋™์œผ๋กœ ์›ํด๋ฆญ ์…‹์—…ํ•ด ์ฃผ๋Š” ๋ฐฐ์น˜ ํŒŒ์ผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  1. .env.example ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜์—ฌ .env ํŒŒ์ผ๋กœ ์ด๋ฆ„ ๋ณ€๊ฒฝ ํ›„ ํ•„์š”ํ•œ ์„ค์ • ์ž…๋ ฅ.(SECURITY_KEY)
  2. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์˜ run_windows.bat ํŒŒ์ผ์„ ๋งˆ์šฐ์Šค ๋”๋ธ”ํด๋ฆญํ•˜์—ฌ ๊ธฐ๋™.
  • run_windows.bat๋Š” ์›น ์„œ๋ฒ„์™€ ์Šค์บ๋„ˆ ์›Œ์ปค๋ฅผ ํ•จ๊ป˜ ๊ธฐ๋™ํ•˜๋„๋ก ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋กœ์ปฌ ํฌํŠธ: http://localhost:5930


๐Ÿ’พ Redis ์บ์‹œ ์—ฐ๋™ ๋ฐ ์„ฑ๋Šฅ ๊ฐ€์ด๋“œ (์„ ํƒ ๋ฐ ๊ถŒ์žฅ)

BookOasis๋Š” ์‹ค์‹œ๊ฐ„ ๋…์„œ ์ง„ํ–‰๋„ ์ €์žฅ ์‹œ SQLite ํŒŒ์ผ์— ๋ฐ”๋กœ ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ  ์ธ๋ฉ”๋ชจ๋ฆฌ(RAM) ์บ์‹œ๋กœ ์™„์ถฉํ•ด ์ฃผ๋Š” Redis ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์บ์‹œ ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋””์Šคํฌ ์“ฐ๊ธฐ ๋ณ‘๋ชฉ์ด ๊ฒฉ๊ฐํ•˜๊ณ  ์Šค์บ” ์ค‘์˜ DB ์†์ƒ(Malformed) ํ˜„์ƒ์ด ์™„๋ฒฝํžˆ ๋ฐฉ์ง€๋ฉ๋‹ˆ๋‹ค.

๐Ÿณ Docker ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ (์™„์ „ ์ž๋™)

  • docker-compose.yml ํ…œํ”Œ๋ฆฟ์— redis:7-alpine ์ด๋ฏธ์ง€ ์—ฐ๋™์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • .env ํŒŒ์ผ์„ ์ˆ˜์ •ํ•  ํ•„์š” ์—†์ด docker compose up -d ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ์ „์šฉ ๋ ˆ๋””์Šค๊ฐ€ ์ผœ์ง€๊ณ  ๊ฒฉ๋ฆฌ ๋„คํŠธ์›Œํฌ ์ƒ์—์„œ ์™„์ „ํžˆ ์ž๋™์œผ๋กœ ํ†ตํ•ฉ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ ์‹œ ์บ์‹œ๊ฐ€ ์œ ์‹ค๋˜์ง€ ์•Š๋„๋ก stop_grace_period์ด 1m(1๋ถ„)์œผ๋กœ ์ƒํ–ฅ ์ง€์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ–ฅ๏ธ Native Python (Linux / Windows) ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ

  1. ํ˜ธ์ŠคํŠธ OS์— ๋ ˆ๋””์Šค ์„œ๋ฒ„๋ฅผ ์„ค์น˜ ๋ฐ ๊ธฐ๋™ํ•ฉ๋‹ˆ๋‹ค. (Ubuntu ์˜ˆ์‹œ: sudo apt install redis-server -y)
  2. .env ํŒŒ์ผ ํ•˜๋‹จ์— ์ ‘์† URL์„ ๊ธฐ์žฌํ•ด ์ค๋‹ˆ๋‹ค.
    REDIS_URL=redis://127.0.0.1:6379/9
    • Tip: ๋‹ค๋ฅธ ๊ธฐ์กด ์„œ๋น„์Šค์™€ ๋ ˆ๋””์Šค๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒฝ์šฐ, DB ๋ฒˆํ˜ธ๋ฅผ /9๋ฒˆ ๋“ฑ ๋‹ค๋ฅธ ์ธ๋ฑ์Šค๋กœ ์ง€์ •ํ•˜๋ฉด ์ถฉ๋Œ์ด ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ ํ‚ค ์•ž์— bookoasis: ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ๊ฐ•์ œ ์ง€์ •๋ฉ๋‹ˆ๋‹ค.
  3. ๋ ˆ๋””์Šค๊ฐ€ ์ค€๋น„๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ ‘์†์— ์‹คํŒจํ•˜๋ฉด ์ž๋™์œผ๋กœ ๊ธฐ์กด์˜ SQLite ์ง์ ‘ ์“ฐ๊ธฐ ๋ชจ๋“œ๋กœ ์šฐํšŒ(Fallback) ํ•˜๋ฏ€๋กœ ์•ˆ์‹ฌํ•˜๊ณ  ์‚ฌ์šฉํ•˜์…”๋„ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ—„๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ ํƒ ๊ฐ€์ด๋“œ (SQLite vs MariaDB)

BookOasis๋Š” ๊ธฐ๋ณธ ํŒŒ์ผ ๊ธฐ๋ฐ˜ SQLite ์—”์ง„ ์™ธ์—๋„, 10๋งŒ ๊ถŒ ์ด์ƒ์˜ ๋Œ€๊ทœ๋ชจ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ๋ฉ€ํ‹ฐ ์‚ฌ์šฉ์ž/๋™์‹œ ์ ‘์† ํ™˜๊ฒฝ์„ ์œ„ํ•œ MariaDB ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—”์ง„์„ ๊ณต์‹ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Š ์—”์ง„ ๋น„๊ต

๊ธฐ๋Šฅ / ํŠน์„ฑ SQLite (๊ธฐ๋ณธ๊ฐ’) MariaDB (์„ ํƒ/๊ถŒ์žฅ)
์„ค์น˜ ๋ฐ ๊ตฌ๋™ ์„ค์ • ์—†์ด ์ฆ‰์‹œ ๊ตฌ๋™ (ํŒŒ์ผ DB) Docker Compose ๋˜๋Š” ๋ณ„๋„ MariaDB ์—ฐ๋™
์ ํ•ฉํ•œ ๊ทœ๋ชจ ๊ฐœ์ธ / ์ค‘์†Œํ˜• ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (5๋งŒ ๊ถŒ ์ดํ•˜) ๋Œ€๊ทœ๋ชจ / ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ (10๋งŒ ๊ถŒ ์ด์ƒ, ๋Œ€์šฉ๋Ÿ‰ ์Šค์บ”)
๋™์‹œ์„ฑ ๋ฐ I/O ํŒŒ์ผ ๋ฝ ๊ธฐ๋ฐ˜ (Redis ์บ์‹œ ๊ถŒ์žฅ) ํ–‰ ๋‹จ์œ„ ๋ฝ(Row-level lock) ๊ณ ์† ๋ถ„์‚ฐ ์ฒ˜๋ฆฌ
๋ฐ์ดํ„ฐ ์•ˆ์ •์„ฑ ๋‹จ์ผ ํŒŒ์ผ ๋ณด๊ด€ DB ํŠธ๋žœ์žญ์…˜, ์ž๋™ ๋ณต๊ตฌ, ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ

๐Ÿš€ MariaDB ๋ชจ๋“œ๋กœ ์ „ํ™˜ํ•˜๊ธฐ

  1. Docker ์‚ฌ์šฉ์ž (์ž๋™/์›ํด๋ฆญ)

    • docker-compose.override.yml์— DB_ENGINE=mariadb ๋ฐ ์ ‘์† ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•œ ๋’ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(media_general, media_adult, media_audiobook) ๋ฐ ์Šคํ‚ค๋งˆ๊ฐ€ ์ž๋™ ๊ตฌ์ถ•๋ฉ๋‹ˆ๋‹ค.
    • GHCR ๊ณต์‹ ์ด๋ฏธ์ง€๋กœ ๋กœ์ปฌ ๋นŒ๋“œ ์—†์ด ๋ฐ”๋กœ ๊ธฐ๋™ํ•˜๋ ค๋ฉด docker-compose.mariadb.ghcr.yml์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
      docker compose -f docker-compose.mariadb.ghcr.yml -f docker-compose.override.yml up -d
      ์†Œ์Šค๋ฅผ ์ง์ ‘ ๋นŒ๋“œํ•˜๋ ค๋ฉด ๊ธฐ์กด docker-compose.mariadb.yml(๋กœ์ปฌ Dockerfile ๋นŒ๋“œ)์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • ์ƒ์„ธ ์ด๊ด€ ์•ˆ๋‚ด: Docker ์‚ฌ์šฉ์ž์šฉ MariaDB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ (docs/move_to_mariadb.md)
  2. 1-Click ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (SQLite โž” MariaDB)

    • ๊ธฐ์กด์— ์ฝ๋˜ ์ฑ…, ์˜ค๋””์˜ค๋ถ ์ง„ํ–‰๋„, ์ฆ๊ฒจ์ฐพ๊ธฐ, ์‚ฌ์šฉ์ž ๊ณ„์ • ๋“ฑ ๊ธฐ์กด SQLite์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์†์‹ค ์—†์ด ํด๋ฆญ ํ•œ ๋ฒˆ์œผ๋กœ MariaDB๋กœ ์ด๊ด€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    python tools/migrator_sqlite_to_mariadb.py

๐Ÿ”‘ ์ดˆ๊ธฐ ๋กœ๊ทธ์ธ ๋ฐ ๊ณ„์ • ์ •๋ณด

  • ์ตœ์ดˆ ์„œ๋ฒ„ ๊ตฌ๋™ ํ›„ ๋กœ๊ทธ์ธ ์‹œ ์•„๋ž˜์˜ ๊ด€๋ฆฌ์ž ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘์†ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž ์ด๋ฆ„(ID): admin
    • ๋น„๋ฐ€๋ฒˆํ˜ธ: admin
  • ๋ณด์•ˆ ๊ถŒ์žฅ: ์ฒซ ๋กœ๊ทธ์ธ ํ›„ ์ฆ‰์‹œ [์„ค์ •] > [๊ณ„์ • ๊ด€๋ฆฌ] ํƒญ์—์„œ ๊ด€๋ฆฌ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•ด ์ฃผ์„ธ์š”.

๐Ÿ›ก๏ธ ํ”„๋ก์‹œ ํ—ค๋” ์ธ์ฆ (Proxy Header Auth / SSO) ๊ฐ€์ด๋“œ

ํ•ด์™ธ ํ™ˆ๋žฉ ์œ ์ € ๋ฐ OIDC ์—ฐ๋™์„ ์œ„ํ•ด Proxy Header Auth (๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ์ž๋™ ๋กœ๊ทธ์ธ) ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. Authelia, Authentik ๋“ฑ ์•ž๋‹จ์˜ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ์ธ์ฆ ์„œ๋ฒ„๊ฐ€ ๊ฒ€์ฆ์„ ๋งˆ์น˜๊ณ  ์ „๋‹ฌํ•˜๋Š” HTTP ํ—ค๋”(Remote-User ๋˜๋Š” X-Forwarded-User) ๊ฐ’์„ ์‹ ๋ขฐํ•˜์—ฌ ์ž๋™์œผ๋กœ BookOasis์— ๋กœ๊ทธ์ธ(SSO)์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Caution

์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ๊ฒฝ๊ณ  ์ด ๊ธฐ๋Šฅ์€ ๋ฐ˜๋“œ์‹œ Nginx, Authelia ๋“ฑ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๊ฐ€ ํ—ค๋”๋ฅผ ๋ณ€์กฐ ๋ฐ ๋ณดํ˜ธํ•˜๋Š” ํ์‡„๋ง ํ™˜๊ฒฝ์—์„œ๋งŒ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค! ํ”„๋ก์‹œ ์—†์ด ์ธํ„ฐ๋„ท์— ๊ฐœ๋ฐฉ๋œ ์ƒํƒœ์—์„œ ์ด ์˜ต์…˜์„ ์ผค ๊ฒฝ์šฐ, ์•…์˜์ ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ํ—ค๋” ์กฐ์ž‘(์˜ˆ: Remote-User: admin)๋งŒ์œผ๋กœ ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์„ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ์‹ฌ๊ฐํ•œ ์ทจ์•ฝ์ ์ด ๋ฉ๋‹ˆ๋‹ค. ์œ„ํ—˜์„ฑ์„ ์ถฉ๋ถ„ํžˆ ์ธ์ง€ํ•œ ๋ถ„๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

์„ค์ • ๋ฐฉ๋ฒ•:

  1. ์–ด๋“œ๋ฏผ ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ํ›„ ์ผ๋ฐ˜ ์„ค์ • ๋ฉ”๋‰ด์— ์ง„์ž…ํ•ฉ๋‹ˆ๋‹ค.
  2. ์Šคํฌ๋กค์„ ๋‚ด๋ ค Proxy Header Auth (๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ์ž๋™ ๋กœ๊ทธ์ธ) ํ•ญ๋ชฉ์„ ์ฐพ์•„ ํ† ๊ธ€ํ•ฉ๋‹ˆ๋‹ค.
  3. ์„ค์ •์„ ์ €์žฅํ•œ ๋’ค, ์•ž๋‹จ์˜ Nginx/ํ”„๋ก์‹œ ์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ์ž๋ช… ํ—ค๋”๋ฅผ BookOasis ๋กœ ๋„˜๊ฒจ์ฃผ๋„๋ก ๊ตฌ์„ฑํ•˜์‹ญ์‹œ์˜ค.

์„ ํƒ ๋ณด์•ˆ ์˜ต์…˜ (๊ถŒ์žฅ):

  • PROXY_HEADER_TRUSTED_IPS: ํ”„๋ก์‹œ ์›๋ณธ IP/CIDR ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ (์˜ˆ: 127.0.0.1,10.0.0.0/8,192.168.0.0/16)
    • ์ด ๊ฐ’์ด ์„ค์ •๋˜๋ฉด, ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ์—†๋Š” ์†Œ์Šค IP์—์„œ ์ „๋‹ฌ๋œ Remote-User/X-Forwarded-User ํ—ค๋”๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.
  • PROXY_HEADER_DENY_DIRECT: 1๋กœ ์„ค์ • ์‹œ, ํ”„๋ก์‹œ ํ—ค๋”๊ฐ€ ์—†๋Š” ์ง์ ‘ ์ ‘์†์„ ๊ฑฐ๋ถ€ (reverse proxy ๊ฒฝ์œ  ๊ฐ•์ œ)

์œ„ ์˜ต์…˜์€ DB ์„ค์ •(settings ํ…Œ์ด๋ธ”) ๋˜๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜(.env)๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DB ์„ค์ •๊ฐ’์ด ์šฐ์„  ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.


Nginx ์„ค์ • ๊ฐ€์ด๋“œ

  1. ์ „์—ญ ์„ค์ • (nginx.conf) ์—…๋ฐ์ดํŠธ Cloudflare๋ฅผ ํ†ตํ•˜๋Š” ์š”์ฒญ์€ ์ผ๋ฐ˜์ ์ธ ์š”์ฒญ๋ณด๋‹ค ํ—ค๋” ํฌ๊ธฐ(์ฟ ํ‚ค, ์ธ์ฆ ํ† ํฐ, ํ”„๋ก์‹œ ํ—ค๋” ๋“ฑ)๊ฐ€ ํ›จ์”ฌ ๋น„๋Œ€ํ•ฉ๋‹ˆ๋‹ค. Nginx์˜ ๊ธฐ๋ณธ ํ—ค๋” ๋ฒ„ํผ ํฌ๊ธฐ๊ฐ€ ์ž‘์œผ๋ฉด ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•˜๊ณ  400 Bad Request ๋˜๋Š” 414 Request-URI Too Large ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด /etc/nginx/nginx.conf ํŒŒ์ผ์˜ http { ... } ๋ธ”๋ก ๋‚ด๋ถ€์— ์•„๋ž˜ ์„ค์ •์„ ๋ฐ˜๋“œ์‹œ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ํ™•์žฅํ•ด ์ฃผ์„ธ์š”.

http {
    # ------------------------------------------------------------------
    # [Cloudflare ๋ฐ ๋Œ€์šฉ๋Ÿ‰ ํ—ค๋” ๋Œ€์‘] ๋ฒ„ํผ ํฌ๊ธฐ ๋Œ€ํญ ํ™•์žฅ
    # ์ฟ ํ‚ค ๋ฐ ์ธ์ฆ ํ—ค๋”๊ฐ€ ๊ธธ์–ด์งˆ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” 4XX ์—๋Ÿฌ๋ฅผ ์›์ฒœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.
    # ------------------------------------------------------------------
    client_header_buffer_size 16k;
    large_client_header_buffers 4 64k;

    # ------------------------------------------------------------------
    # ํ”„๋ก์‹œ ํ—ค๋” ํ•ด์‹œ ํฌ๊ธฐ ์ตœ์ ํ™”
    # ๋‹ค์ˆ˜์˜ ๋ณต์žกํ•œ X-Forwarded-* ํ—ค๋”๊ฐ€ ์œ ์ž…๋˜์–ด๋„ ํ•ด์‹œ ํ…Œ์ด๋ธ” ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ๋‚˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    # ------------------------------------------------------------------
    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;

    # (๊ธฐ์กด์˜ ๋‹ค๋ฅธ ์„ค์ •๋“ค...)
}
  1. BookOasis ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ ์„ค์ • (sites-available) /etc/nginx/sites-available/default ํŒŒ์ผ(๋˜๋Š” ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ ์„ค์ • ๋ธ”๋ก)์— ์•„๋ž˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๊ณ , sites-enabled์— ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ๊ฑธ์–ด ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
# ------------------------------------------------------------------
# ๋ฐฑ์—”๋“œ ์˜๊ตฌ ์ปค๋„ฅ์…˜ ํ’€ ์„ค์ • (์†Œ์ผ“ ์ƒ์„ฑ ์ง€์—ฐ 0ms)
# ------------------------------------------------------------------
upstream bookoasis_backend {
    server 127.0.0.1:5930;
    keepalive 64; # 64๊ฐœ ๋ฐฑ์—”๋“œ ์ปค๋„ฅ์…˜์„ ์˜๊ตฌ ์œ ์ง€ํ•˜์—ฌ ์—ฐ๊ฒฐ ์†Œ๋ชจ ๋ฐฉ์ง€
}

server {
    listen 80;
    server_name your-domain.com; # <== ๋ณธ์ธ์˜ ๋„๋ฉ”์ธ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.

    # HTTP๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ HTTPS๋กœ ๊ฐ•์ œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ (๋ณด์•ˆ)
    if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri/;
    }

    # ------------------------------------------------------------------
    # Gzip ํ…์ŠคํŠธ ๋ฐ SVG ์••์ถ• ์„ค์ • (UI ๋ฐ JSON API ๊ฐ€์†)
    # ------------------------------------------------------------------
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;

    # ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ฐ ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ๊ณ ๋ คํ•œ ๋ฐ”๋”” ํฌ๊ธฐ ์ œํ•œ
    client_max_body_size 100M;

    # ------------------------------------------------------------------
    # ๋ณด์•ˆ ํ—ค๋” ์ฃผ์ž…
    # ------------------------------------------------------------------
    add_header X-Frame-Options "SAMEORIGIN" always;         # ํด๋ฆญ์žฌํ‚น ๋ฐฉ์ง€
    add_header X-Content-Type-Options "nosniff" always;     # MIME ์Šค๋‹ˆํ•‘ ๋ฐฉ์ง€
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # ------------------------------------------------------------------
    # 1. ์ปค๋ฒ„ ์ด๋ฏธ์ง€ ๋ผ์šฐํŒ… ์ตœ์ ํ™”
    # ------------------------------------------------------------------
    # 1-1. ๋™์  SVG ์ปค๋ฒ„ ์ƒ์„ฑ API (๋ฐฑ์—”๋“œ ํŒŒ์ด์ฌ์œผ๋กœ ์ „๋‹ฌ)
    location /covers/fallback {
        proxy_pass http://bookoasis_backend;
        proxy_set_header Host $http_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 $http_x_forwarded_proto;
    }

    # 1-2. ์ปค๋ฒ„ ์ด๋ฏธ์ง€ ์ •์  ์„œ๋น™ ์ตœ์ ํ™” (ํŒŒ์ด์ฌ ์šฐํšŒ ๋‹ค์ด๋ ‰ํŠธ 0ms ์„œ๋น™)
    location /covers/ {
        alias /path/to/media_server/covers/; # <== ๋ณธ์ธ์˜ ์„ค์น˜ ๊ฒฝ๋กœ/covers/ ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.
        expires 1d;
        add_header Cache-Control "public, max-age=86400";
        sendfile on;
        tcp_nopush on;
    }

    # ------------------------------------------------------------------
    # 2. ์ผ๋ฐ˜ API ๋ฐ ๋ฉ”์ธ ์›น ์„œ๋น„์Šค (WebSocket ์ง€์›)
    # ------------------------------------------------------------------
    location / {
        proxy_pass http://bookoasis_backend/;

        # [๊ธฐ๋ณธ ํ”„๋ก์‹œ ํ—ค๋” ์„ค์ •]
        proxy_set_header Host $http_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 $http_x_forwarded_proto;

        # [WebSocket ๋ฐ HTTP/1.1 ํ”„๋กœํ† ์ฝœ ์—…๊ทธ๋ ˆ์ด๋“œ ์ง€์›]
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # [CRITICAL] ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ „์†ก ์ตœ์ ํ™” (ํ”„๋ก์‹œ ๋ฒ„ํผ๋ง ๋”)
        proxy_buffering off;

        # [ํƒ€์ž„์•„์›ƒ ํ™•์žฅ] ๋Œ€์šฉ๋Ÿ‰ ์Šค์บ” ํ”„๋กœ์„ธ์Šค ๋ฐ ์žฅ์‹œ๊ฐ„ ์ž‘์—… ๋Œ€์‘
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
    }
}

๐ŸŽง ์˜ค๋””์˜ค๋ถ ์ŠคํŠธ๋ฆฌ๋ฐ ์•ˆ์ •ํ™” ๊ฐ€์ด๋“œ (Nginx / Cloudflare)

์˜ค๋””์˜ค๋ถ ์Šค์บ”์ด ์ •์ƒ(BOOK_PROCESSED, duration_sec > 0)์ด์–ด๋„, ์•ž๋‹จ ํ”„๋ก์‹œ/CDN์—์„œ Range ์š”์ฒญ์ด ๋ณ€ํ˜•๋˜๊ฑฐ๋‚˜ ์บ์‹œ๊ฐ€ ์ž˜๋ชป ์ ์šฉ๋˜๋ฉด ์žฌ์ƒ์ด ๋ฉˆ์ถ”๊ฑฐ๋‚˜ 0:00์œผ๋กœ ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ถŒ์žฅ ์„ค์ •

  1. Cloudflare ์บ์‹œ ์šฐํšŒ ๊ทœ์น™ ์ถ”๊ฐ€ (๊ถŒ์žฅ)
  • ๊ฒฝ๋กœ ์˜ˆ์‹œ:
    • /api/media/audiobooks/*/tracks/*/stream
  • Cache Level: Bypass
  • Performance/Optimization ๊ณ„์—ด์—์„œ ์˜ค๋””์˜ค ์ŠคํŠธ๋ฆผ URL์— ๋Œ€ํ•œ ๋ณ€ํ™˜(Transform/Minify/Polish ๋“ฑ)์ด ์ ์šฉ๋˜์ง€ ์•Š๋„๋ก ์ œ์™ธ
  1. Nginx์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐ ๊ฒฝ๋กœ ๋ฒ„ํผ๋ง ๋น„ํ™œ์„ฑํ™” (๊ถŒ์žฅ)
  • ์ „์ฒด location /์— proxy_buffering off;๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด ๊ทธ๋Œ€๋กœ ์œ ์ง€
  • ๋ณ„๋„ location์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ ์•„๋ž˜์ฒ˜๋Ÿผ ๋™์ผ ์ •์ฑ… ์œ ์ง€
location ~ ^/api/media/audiobooks/.*/tracks/.*/stream$ {
   proxy_pass http://bookoasis_backend;
   proxy_http_version 1.1;
   proxy_set_header Host $http_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 $http_x_forwarded_proto;

   # ์˜ค๋””์˜ค ์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์—ฐ/๋Š๊น€ ๋ฐฉ์ง€
   proxy_buffering off;

   # ์žฅ์‹œ๊ฐ„ ์ฒญ์ทจ ์„ธ์…˜ ๋Œ€์‘
   proxy_read_timeout 3600;
   proxy_send_timeout 3600;
}

๋น ๋ฅธ ์ ๊ฒ€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž๋„๊ตฌ Network์—์„œ ์ŠคํŠธ๋ฆผ ์š”์ฒญ ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ 206 Partial Content์ธ์ง€ ํ™•์ธ
  • ์ŠคํŠธ๋ฆผ ์š”์ฒญ์ด ๋ฐ˜๋ณต 404๋ผ๋ฉด DB ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹คํ–‰ ์ค‘์ธ ์›น ํ”„๋กœ์„ธ์Šค์˜ ์‹ค์ œ ํŒŒ์ผ ์ ‘๊ทผ ๊ฒฝ๋กœ/๋งˆ์šดํŠธ ์ƒํƒœ๋ฅผ ์šฐ์„  ์ ๊ฒ€
  • ์žฌ์ƒ ์‹คํŒจ ์งํ›„ current_time=0 ์ €์žฅ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์›์ธ ํŒŒ์•… ์ „์—๋Š” ์‹คํŒจ ์žฌ์ƒ ๋ฐ˜๋ณต ํ…Œ์ŠคํŠธ๋ฅผ ํ”ผํ•˜๊ณ  ์ŠคํŠธ๋ฆผ ์‘๋‹ต ์ฝ”๋“œ๋ถ€ํ„ฐ ํ™•์ธ

Caddy ์„ค์ • ๊ฐ€์ด๋“œ

Nginx ๋Œ€์‹  Caddy๋ฅผ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด Caddyfile์„ ๊ตฌ์„ฑํ•˜์—ฌ ์ตœ์ ํ™” ๋ฐ ์—ฐ๋™์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Caddy๋Š” ์ž๋™์œผ๋กœ SSL ์ธ์ฆ์„œ(HTTPS)๋ฅผ ๋ฐœ๊ธ‰ ๋ฐ ๊ด€๋ฆฌํ•ด์ฃผ๋ฉฐ, WebSocket๊ณผ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ํ—ค๋” ์ฒ˜๋ฆฌ๋ฅผ ๊ธฐ๋ณธ ๋‚ด์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

/etc/caddy/Caddyfile ํŒŒ์ผ์— ๋ณธ์ธ์˜ ๋„๋ฉ”์ธ์„ ๋งคํ•‘ํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚ด์šฉ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

your-domain.com { # <== ๋ณธ์ธ์˜ ๋„๋ฉ”์ธ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.
    # ------------------------------------------------------------------
    # Gzip ๋ฐ Zstd ํ…์ŠคํŠธ ์••์ถ• ์„ค์ • (UI ๋ฐ JSON API ๊ฐ€์†)
    # ------------------------------------------------------------------
    encode gzip zstd

    # ------------------------------------------------------------------
    # ์ตœ๋Œ€ ๋ฐ”๋”” ํฌ๊ธฐ ์ œํ•œ (Nginx client_max_body_size 100M ๋Œ€์‘)
    # ์•Œ๋ผ๋”˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋“ฑ ์ปค๋ฒ„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๋ฅผ ๊ณ ๋ คํ•œ ํ•œ๋„์ž…๋‹ˆ๋‹ค.
    # ------------------------------------------------------------------
    request_body {
        max_size 100mb
    }

    # ------------------------------------------------------------------
    # ๋ฉ”์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋ก์‹œ ๋ผ์šฐํŒ…
    # ------------------------------------------------------------------
    reverse_proxy 127.0.0.1:5930 {
        # [CRITICAL] ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ „์†ก ์ตœ์ ํ™” (ํ”„๋ก์‹œ ๋ฒ„ํผ๋ง ๋น„ํ™œ์„ฑํ™”)
        # BookOasis์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ธ '์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ'์ด ํ”„๋ก์‹œ ๋ฒ„ํผ์—
        # ๊ฐ€๋กœ๋ง‰ํžˆ์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์ „์†ก๋˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
        flush_interval -1
    }
}

๋ณ€๊ฒฝ ์™„๋ฃŒ ํ›„ sudo systemctl reload caddy ๋ช…๋ น์„ ํ†ตํ•ด Caddy ์„ค์ •์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

๋ผ์ด์„ ์Šค ๋ฐ ์ƒํ‘œ๊ถŒ ์ •๋ณด

  • ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด์„ ์Šค: ๋ณธ ํ”„๋กœ์ ํŠธ๋Š” GNU AGPLv3 (Affero General Public License v3.0) ๊ทœ๊ฒฉ์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ๋ˆ„๊ตฌ๋‚˜ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์—ด๋žŒ, ์ˆ˜์ •, ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์„œ๋น„์Šค(๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•œ ์„œ๋น„์Šค ํฌํ•จ)๋ฅผ ์ œ๊ณตํ•  ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ ์ˆ˜์ •๋œ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋™์ผํ•œ AGPLv3 ๋ผ์ด์„ ์Šค๋กœ ๊ณต๊ฐœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์•ฝ๊ด€์€ LICENSE ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.
  • ์ƒํ‘œ๊ถŒ ๋ณดํ˜ธ ๊ฐ€์ด๋“œ๋ผ์ธ: "BookOasis" ๋ช…์นญ ๋ฐ ๊ด€๋ จ ๊ณต์‹ ๋กœ๊ณ  ์ด๋ฏธ์ง€๋Š” ์›์ž‘์ž์˜ ๊ณ ์œ  ์‹๋ณ„ ์ƒํ‘œ(Trademark)๋กœ ๋ณดํ˜ธ๋ฉ๋‹ˆ๋‹ค. ๋ณธ ํ”„๋กœ๊ทธ๋žจ์„ ํฌํฌ(Fork) ๋ฐ ๋ณ€๊ฒฝํ•˜์—ฌ ์žฌ๋ฐฐํฌ ์‹œ ์›๋ณธ ์†Œ์Šค์ฝ”๋“œ์˜ ์ €์ž‘๊ถŒ ํ‘œ๊ธฐ๋Š” ์„ฑ์‹คํžˆ ์ค€์ˆ˜ํ•˜๋˜, ๋™์ผํ•œ ๋ช…์นญ("BookOasis")๊ณผ ๊ณต์‹ ๋กœ๊ณ ๋ฅผ ์ œํ’ˆ๋ช…์— ์‚ฌ์šฉํ•˜์—ฌ ์žฌ๋ฐฐํฌํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ๋ฐ˜๋“œ์‹œ ์ด๋ฆ„์„ ๋‹ค๋ฅด๊ฒŒ ๋ณ€๊ฒฝํ•˜์—ฌ ์‹๋ณ„๋˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Copyright ยฉ 2026 leeyj (Carls, leeyj78@gmail.com). All rights reserved.

About

A lightweight, high-performance alternative to Kavita, Komga, and Stump for streaming books and comics (ZIP/CBZ/EPUB/PDF) directly from remote storage

Topics

Resources

Stars

53 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages