์–‘์ž ๋‚ด์„ฑ ์ด๋ฉ”์ผ: ์•”ํ˜ธํ™”๋œ SQLite ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฉ”์ผ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•

์–‘์ž ์•ˆ์ „ ์•”ํ˜ธํ™” ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์ผ๋Ÿฌ์ŠคํŠธ

์„œ๋ฌธ

Important

์ €ํฌ ์ด๋ฉ”์ผ ์„œ๋น„์Šค๋Š” 100% ์˜คํ”ˆ์†Œ์Šค์ด๋ฉฐ ์•ˆ์ „ํ•˜๊ณ  ์•”ํ˜ธํ™”๋œ SQLite ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ํ†ตํ•ด ํ”„๋ผ์ด๋ฒ„์‹œ๋ฅผ ์ค‘์‹œํ•ฉ๋‹ˆ๋‹ค.

IMAP ์ง€์›์„ ์ถœ์‹œํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” MongoDB๋ฅผ ์˜๊ตฌ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ์ˆ ์€ ํ›Œ๋ฅญํ•˜๋ฉฐ ์ง€๊ธˆ๋„ ์‚ฌ์šฉ ์ค‘์ด์ง€๋งŒ, MongoDB์—์„œ ์•”ํ˜ธํ™”๋œ ์ €์žฅ(Encryption-at-rest)์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Digital Ocean์ด๋‚˜ Mongo Atlas ๊ฐ™์€ MongoDB Enterprise๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ณต๊ธ‰์ž๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๋ผ์ด์„ ์Šค๋ฅผ ๊ตฌ๋งคํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ์ดํ›„์—๋Š” ์˜์—…ํŒ€๊ณผ์˜ ์ง€์—ฐ ๋ฌธ์ œ๋„ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค).

Forward Email ํŒ€์€ ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ด๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๊ณ  ์•”ํ˜ธํ™”๋œ IMAP ๋ฉ”์ผ๋ฐ•์Šค ์ €์žฅ ์†”๋ฃจ์…˜์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ์ž๋กœ์„œ ์•”ํ˜ธํ™”๋œ ์ €์žฅ ๊ธฐ๋Šฅ์„ ์œ„ํ•ด ๋ผ์ด์„ ์Šค ๋น„์šฉ์„ ์ง€๋ถˆํ•ด์•ผ ํ•˜๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ €ํฌ ์›์น™์— ๋ฐ˜ํ–ˆ๊ธฐ์—, ์ง์ ‘ ์‹คํ—˜ํ•˜๊ณ  ์—ฐ๊ตฌํ•˜๋ฉฐ ์ด ์š”๊ตฌ๋ฅผ ํ•ด๊ฒฐํ•  ์ƒˆ๋กœ์šด ์†”๋ฃจ์…˜์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ฐœ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ์ €์žฅํ•˜๋Š” ๋Œ€์‹ , ๊ฐ ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์•”ํ˜ธํ™”ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ(์‚ฌ์šฉ์ž๋งŒ ์•Œ๊ณ  ์žˆ์Œ)๋กœ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ €ํฌ ์ด๋ฉ”์ผ ์„œ๋น„์Šค๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์žŠ์œผ๋ฉด ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ์žƒ๊ฒŒ ๋  ์ •๋„๋กœ ๋งค์šฐ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค (์˜คํ”„๋ผ์ธ ๋ฐฑ์—…์œผ๋กœ ๋ณต๊ตฌํ•˜๊ฑฐ๋‚˜ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค).

์•„๋ž˜์—์„œ ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์ œ๊ณต์ž ๋น„๊ต, ์„œ๋น„์Šค ์ž‘๋™ ๋ฐฉ์‹, ๊ธฐ์ˆ  ์Šคํƒ ๋“ฑ์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์„ธ์š”.

์ด๋ฉ”์ผ ์„œ๋น„์Šค ์ œ๊ณต์ž ๋น„๊ต

์ €ํฌ๋Š” ๊ฐœ๋ณ„ ์•”ํ˜ธํ™”๋œ SQLite ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ฌด์ œํ•œ ๋„๋ฉ”์ธ, ๋ณ„์นญ, ์‚ฌ์šฉ์ž๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ ์•„์›ƒ๋ฐ”์šด๋“œ SMTP, IMAP, POP3๋ฅผ ์ง€์›ํ•˜๋Š” ์œ ์ผํ•œ 100% ์˜คํ”ˆ์†Œ์Šค ๋ฐ ํ”„๋ผ์ด๋ฒ„์‹œ ์ค‘์‹ฌ ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์ œ๊ณต์ž์ž…๋‹ˆ๋‹ค:

๋‹ค๋ฅธ ์ด๋ฉ”์ผ ์ œ๊ณต์ž์™€ ๋‹ฌ๋ฆฌ Forward Email์—์„œ๋Š” ๋„๋ฉ”์ธ ๋˜๋Š” ๋ณ„์นญ๋ณ„๋กœ ์ €์žฅ ๊ณต๊ฐ„ ๋น„์šฉ์„ ์ง€๋ถˆํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ €์žฅ ๊ณต๊ฐ„์€ ์ „์ฒด ๊ณ„์ •์— ๊ฑธ์ณ ๊ณต์œ ๋˜๋ฏ€๋กœ ์—ฌ๋Ÿฌ ๋งž์ถค ๋„๋ฉ”์ธ๊ณผ ๊ฐ ๋„๋ฉ”์ธ๋ณ„ ์—ฌ๋Ÿฌ ๋ณ„์นญ์ด ์žˆ์–ด๋„ ์™„๋ฒฝํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ์›ํ•œ๋‹ค๋ฉด ๋„๋ฉ”์ธ ๋˜๋Š” ๋ณ„์นญ๋ณ„ ์ €์žฅ ๊ณต๊ฐ„ ์ œํ•œ์„ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฉ”์ผ ์„œ๋น„์Šค ๋น„๊ต ์ฝ๊ธฐ

์ž‘๋™ ์›๋ฆฌ

  1. Apple Mail, Thunderbird, Gmail, Outlook ๊ฐ™์€ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์ €ํฌ ์•ˆ์ „ํ•œ IMAP ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค:

    • ์‚ฌ์šฉ์ž ์ด๋ฆ„์€ hello@example.com ๊ฐ™์€ ๋„๋ฉ”์ธ์ด ํฌํ•จ๋œ ์ „์ฒด ๋ณ„์นญ์ž…๋‹ˆ๋‹ค.
    • ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ฌด์ž‘์œ„๋กœ ์ƒ์„ฑ๋˜๋ฉฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ƒ์„ฑ์„ ํด๋ฆญํ•  ๋•Œ๋งŒ 30์ดˆ ๋™์•ˆ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฒ„ํŠผ์€ ๋‚ด ๊ณ„์ • ๋„๋ฉ”์ธ ๋ณ„์นญ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์—ฐ๊ฒฐ๋˜๋ฉด, ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๋Š” IMAP ํ”„๋กœํ† ์ฝœ ๋ช…๋ น์–ด๋ฅผ ์šฐ๋ฆฌ IMAP ์„œ๋ฒ„์— ๋ณด๋‚ด์„œ ๋ฉ”์ผํ•จ์„ ๋™๊ธฐํ™” ์ƒํƒœ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ž„์‹œ ์ €์žฅ๋œ ์ด๋ฉ”์ผ ์ž‘์„ฑ ๋ฐ ์ €์žฅ๊ณผ ์‚ฌ์šฉ์ž๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํƒ€ ์ž‘์—…(์˜ˆ: ์ด๋ฉ”์ผ์„ ์ค‘์š” ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜ ์ŠคํŒธ/์ •ํฌ ๋ฉ”์ผ๋กœ ํ”Œ๋ž˜๊ทธ ์ง€์ •)์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  3. ๋ฉ”์ผ ๊ตํ™˜ ์„œ๋ฒ„(์ผ๋ฐ˜์ ์œผ๋กœ "MX" ์„œ๋ฒ„๋ผ๊ณ  ํ•จ)๋Š” ์ƒˆ๋กœ ๋“ค์–ด์˜ค๋Š” ์ด๋ฉ”์ผ์„ ๋ฐ›์•„์„œ ๋ฉ”์ผํ•จ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์•Œ๋ฆผ์„ ๋ฐ›๊ณ  ๋ฉ”์ผํ•จ์„ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋ฉ”์ผ ๊ตํ™˜ ์„œ๋ฒ„๋Š” ์ด๋ฉ”์ผ์„ ํ•œ ๋ช… ์ด์ƒ์˜ ์ˆ˜์‹ ์ž(ํฌํ•จ ์›นํ›…)์—๊ฒŒ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, ์•”ํ˜ธํ™”๋œ IMAP ์ €์žฅ์†Œ์— ์ด๋ฉ”์ผ์„ ์ €์žฅํ•˜๊ฑฐ๋‚˜, ๋‘˜ ๋‹ค ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

    Tip

    ๋” ์•Œ๊ณ  ์‹ถ์œผ์‹ ๊ฐ€์š”? ์ด๋ฉ”์ผ ์ „๋‹ฌ ์„ค์ • ๋ฐฉ๋ฒ•, ๋ฉ”์ผ ๊ตํ™˜ ์„œ๋น„์Šค ์ž‘๋™ ๋ฐฉ์‹, ๋˜๋Š” ๊ฐ€์ด๋“œ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

  4. ๋‚ด๋ถ€์ ์œผ๋กœ, ์šฐ๋ฆฌ์˜ ์•ˆ์ „ํ•œ ์ด๋ฉ”์ผ ์ €์žฅ ์„ค๊ณ„๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฉ”์ผํ•จ์„ ์•”ํ˜ธํ™”ํ•˜๊ณ  ์˜ค์ง ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค:

    • ๋ฐœ์‹ ์ž๋กœ๋ถ€ํ„ฐ ์ƒˆ ๋ฉ”์ผ์ด ์ˆ˜์‹ ๋˜๋ฉด, ๋ฉ”์ผ ๊ตํ™˜ ์„œ๋ฒ„๋Š” ๊ฐœ๋ณ„์ ์ด๊ณ  ์ž„์‹œ์ด๋ฉฐ ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผํ•จ์— ๋ฉ”์ผ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

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

    • IMAP์— ์—ฐ๊ฒฐ๋œ ๊ฒฝ์šฐ(์˜ˆ: Apple Mail ๋˜๋Š” Thunderbird ๊ฐ™์€ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ), ์ž„์‹œ ๋””์Šคํฌ ์ €์žฅ์†Œ์— ์“ธ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ฉ”๋ชจ๋ฆฌ ๋‚ด ์•”ํ˜ธํ™”๋œ IMAP ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์ „๋‹ฌ๋  ๋•Œ, ๋ชจ๋“  IMAP ์„œ๋ฒ„์— ํ™œ์„ฑ ์„ธ์…˜์ด ์žˆ๋Š”์ง€ ๋ฌป๋Š” WebSocket ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ (์ด๊ฒƒ์ด ๊ฐ€์ ธ์˜ค๊ธฐ ๋ถ€๋ถ„), ์ด์–ด์„œ ์•”ํ˜ธํ™”๋œ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค โ€“ ๋”ฐ๋ผ์„œ ์ž„์‹œ ๋ฉ”์ผํ•จ์— ์“ธ ํ•„์š” ์—†์ด ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์ œ ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผํ•จ์— ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  5. ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผํ•จ์˜ ๋ฐฑ์—…์€ ๋งค์ผ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์–ธ์ œ๋“  ์ƒˆ ๋ฐฑ์—…์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋‚ด ๊ณ„์ • ๋„๋ฉ”์ธ ๋ณ„์นญ์—์„œ ์ตœ์‹  ๋ฐฑ์—…์„ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฉ”์ผ ์„œ๋น„์Šค๋กœ ์ „ํ™˜ํ•  ๊ฒฝ์šฐ, ์–ธ์ œ๋“  ๋ฉ”์ผํ•จ๊ณผ ๋ฐฑ์—…์„ ์‰ฝ๊ฒŒ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ๋‹ค์šด๋กœ๋“œ, ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ 

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ ๊ณ„์ธต๋„ ๊ฒ€ํ† ํ–ˆ์ง€๋งŒ, SQLite๋งŒํผ ์šฐ๋ฆฌ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑ์‹œํ‚ค๋Š” ๊ฒƒ์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค:

Database Encryption-at-rest Sandboxed Mailboxes License Used Everywhere
SQLite โญ โœ… SQLite3MultipleCiphers์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ โœ… โœ… ํผ๋ธ”๋ฆญ ๋„๋ฉ”์ธ โœ…
MongoDB โŒ "MongoDB Enterprise์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ" โŒ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โŒ AGPL ๋ฐ SSPL-1.0 โŒ
rqlite โŒ ๋„คํŠธ์›Œํฌ ์ „์šฉ โŒ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โœ… MIT โŒ
dqlite โŒ ํ…Œ์ŠคํŠธ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์•„์ง ์ง€์›๋˜์ง€ ์•Š์Œ? โŒ ํ…Œ์ŠคํŠธ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์•„์ง ์ง€์›๋˜์ง€ ์•Š์Œ? โœ… LGPL-3.0-only โŒ
PostgreSQL โœ… ์˜ˆ โŒ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โœ… PostgreSQL (BSD ๋˜๋Š” MIT์™€ ์œ ์‚ฌ) โŒ
MariaDB โœ… InnoDB ์ „์šฉ โŒ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โœ… GPLv2 ๋ฐ BUSL-1.1 โŒ
CockroachDB โŒ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ „์šฉ ๊ธฐ๋Šฅ โŒ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โŒ BUSL-1.1 ๋“ฑ โŒ

์œ„ ํ‘œ์—์„œ ์—ฌ๋Ÿฌ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ ์˜ต์…˜์„ ๋น„๊ตํ•œ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Security

ํ•ญ์ƒ ์šฐ๋ฆฌ๋Š” encryption-at-rest (AES-256), encryption-in-transit (TLS), ๐ŸŠ Tangerine๋ฅผ ์‚ฌ์šฉํ•˜๋Š” DNS over HTTPS("DoH"), ๊ทธ๋ฆฌ๊ณ  ๋ฉ”์ผ๋ฐ•์Šค์— ๋Œ€ํ•œ sqleet (ChaCha20-Poly1305) ์•”ํ˜ธํ™”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ, ์šฐ๋ฆฌ๋Š” ํ† ํฐ ๊ธฐ๋ฐ˜ 2๋‹จ๊ณ„ ์ธ์ฆ(SMS๋Š” ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๋ฏ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ), ๋ฃจํŠธ ์ ‘๊ทผ์ด ๋น„ํ™œ์„ฑํ™”๋œ ํšŒ์ „ SSH ํ‚ค, ์ œํ•œ๋œ IP ์ฃผ์†Œ๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ๋…์  ์ ‘๊ทผ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ณด์•ˆ ์กฐ์น˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์•…์˜์ ์ธ ๋ฉ”์ด๋“œ ๊ณต๊ฒฉ ๋˜๋Š” ์ œ3์ž ๋ฒค๋”์˜ ์•…์„ฑ ์ง์›์ด ๋ฐœ์ƒํ•˜๋”๋ผ๋„, ๊ท€ํ•˜์˜ ๋ฉ”์ผ๋ฐ•์Šค๋Š” ์˜ค์ง ๊ท€ํ•˜๊ฐ€ ์ƒ์„ฑํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ๋งŒ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆ์‹ฌํ•˜์„ธ์š”, ์šฐ๋ฆฌ๋Š” Cloudflare, DataPacket, Digital Ocean, GitHub, Vultr์˜ SOC Type 2 ์ค€์ˆ˜ ์„œ๋ฒ„ ์ œ๊ณต์—…์ฒด ์™ธ์—๋Š” ์–ด๋–ค ์ œ3์ž ๋ฒค๋”์—๋„ ์˜์กดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ๋‹จ์ผ ์‹คํŒจ ์ง€์ ์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฉ”์ผ๋ฐ•์Šค

์š”์•ฝ; ์šฐ๋ฆฌ์˜ IMAP ์„œ๋ฒ„๋Š” ๊ฐ ๋ฉ”์ผ๋ฐ•์Šค๋งˆ๋‹ค ๊ฐœ๋ณ„์ ์œผ๋กœ ์•”ํ˜ธํ™”๋œ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

SQLite๋Š” ๋งค์šฐ ์ธ๊ธฐ ์žˆ๋Š” ์ž„๋ฒ ๋””๋“œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ, ํ˜„์žฌ ๊ท€ํ•˜์˜ ํœด๋Œ€ํฐ๊ณผ ์ปดํ“จํ„ฐ์—์„œ ์‹คํ–‰ ์ค‘์ด๋ฉฐ โ€“ ๊ฑฐ์˜ ๋ชจ๋“  ์ฃผ์š” ๊ธฐ์ˆ ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ์˜ ์•”ํ˜ธํ™”๋œ ์„œ๋ฒ„์—๋Š” linux@example.com, info@example.com, hello@example.com ๋“ฑ์˜ ๋ฉ”์ผ๋ฐ•์Šค๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ .sqlite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒŒ์ผ๋กœ ๋œ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒŒ์ผ ์ด๋ฆ„์„ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ์ง“์ง€ ์•Š๊ณ , ๋Œ€์‹  BSON ObjectID์™€ ๊ณ ์œ  UUID๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฉ”์ผ๋ฐ•์Šค ์†Œ์œ ์ž๋‚˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์•Œ ์ˆ˜ ์—†๋„๋ก ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: 353a03f21e534321f5d6e267.sqlite).

๊ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๊ท€ํ•˜๋งŒ ์•Œ๊ณ  ์žˆ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ sqleet (ChaCha20-Poly1305)๋กœ ์ž์ฒด ์•”ํ˜ธํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ท€ํ•˜์˜ ๋ฉ”์ผ๋ฐ•์Šค๊ฐ€ ๊ฐœ๋ณ„์ ์œผ๋กœ ์•”ํ˜ธํ™”๋˜๊ณ , ๋…๋ฆฝ์ ์ด๋ฉฐ, ์ƒŒ๋“œ๋ฐ•์Šค ์ฒ˜๋ฆฌ๋˜๊ณ , ํœด๋Œ€ ๊ฐ€๋Šฅํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋‹ค์Œ PRAGMA๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SQLite๋ฅผ ๋ฏธ์„ธ ์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค:

PRAGMA ๋ชฉ์ 
cipher=chacha20 ChaCha20-Poly1305 SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•”ํ˜ธํ™”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํ”„๋กœ์ ํŠธ ์•„๋ž˜์˜ better-sqlite3-multiple-ciphers๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.
key="****************" ์ด๊ฒƒ์€ ๊ท€ํ•˜์˜ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ IMAP ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์—์„œ๋งŒ ๋ณตํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค. ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ ์„ธ์…˜๋งˆ๋‹ค ์ƒˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๋‹ซํ˜€ ์ƒŒ๋“œ๋ฐ•์‹ฑ๊ณผ ๊ฒฉ๋ฆฌ๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
journal_mode=WAL ์“ฐ๊ธฐ ์•ž์„œ ๋กœ๊ทธ("WAL") ์„ฑ๋Šฅ ํ–ฅ์ƒ ๋ฐ ๋™์‹œ ์ฝ๊ธฐ ์ ‘๊ทผ ํ—ˆ์šฉ.
busy_timeout=5000 ๋‹ค๋ฅธ ์“ฐ๊ธฐ ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ผ ๋•Œ ์“ฐ๊ธฐ ์ž ๊ธˆ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ จ ์ •๋ณด.
synchronous=NORMAL ๋ฐ์ดํ„ฐ ์†์ƒ ์œ„ํ—˜ ์—†์ด ํŠธ๋žœ์žญ์…˜ ๋‚ด๊ตฌ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค. ๊ด€๋ จ ์ •๋ณด.
foreign_keys=ON ์™ธ๋ž˜ ํ‚ค ์ฐธ์กฐ(์˜ˆ: ํ•œ ํ…Œ์ด๋ธ”์—์„œ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”๋กœ์˜ ๊ด€๊ณ„)๋ฅผ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ SQLite์—์„œ๋Š” ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์ง€๋งŒ, ๊ฒ€์ฆ๊ณผ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ์œ„ํ•ด ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
encoding='UTF-8' ๊ฐœ๋ฐœ์ž์˜ ํŽธ์˜๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ์ธ์ฝ”๋”ฉ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  ๋‹ค๋ฅธ ๊ธฐ๋ณธ๊ฐ’์€ ๊ณต์‹ PRAGMA ๋ฌธ์„œ์— ๋ช…์‹œ๋œ SQLite์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋™์‹œ์„ฑ

์š”์•ฝ; ์•”ํ˜ธํ™”๋œ SQLite ๋ฉ”์ผ๋ฐ•์Šค์— ๋Œ€ํ•œ ๋™์‹œ ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•ด WebSocket์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฝ๊ธฐ

ํœด๋Œ€ํฐ์˜ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๋Š” imap.forwardemail.net์„ ๋‹น์‚ฌ์˜ Digital Ocean IP ์ฃผ์†Œ ์ค‘ ํ•˜๋‚˜๋กœ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ์Šคํฌํ†ฑ ํด๋ผ์ด์–ธํŠธ๋Š” ์ „ํ˜€ ๋‹ค๋ฅธ ์ œ๊ณต์ž์˜ ๋ณ„๋„ IP๋ฅผ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ค IMAP ์„œ๋ฒ„์— ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜๋“ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ 100% ์ •ํ™•ํ•˜๊ฒŒ ์ฝ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” WebSocket์„ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

์“ฐ๊ธฐ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์“ฐ๊ธฐ๋Š” ์•ฝ๊ฐ„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค โ€“ SQLite๋Š” ์ž„๋ฒ ๋””๋“œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉ”์ผ๋ฐ•์Šค๊ฐ€ ๋‹จ์ผ ํŒŒ์ผ์— ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์— litestream, rqlite, dqlite์™€ ๊ฐ™์€ ์˜ต์…˜์„ ํƒ์ƒ‰ํ–ˆ์œผ๋‚˜, ์–ด๋А ๊ฒƒ๋„ ์šฐ๋ฆฌ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

์“ฐ๊ธฐ ์ „ ๋กœ๊ทธ ๊ธฐ๋ก("WAL")์ด ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ ์“ฐ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด, ๋‹จ ํ•˜๋‚˜์˜ ์„œ๋ฒ„("Primary")๋งŒ์ด ์ด๋ฅผ ๋‹ด๋‹นํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. WAL์€ ๋™์‹œ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค๋ฉฐ ํ•œ ๋ช…์˜ ์ž‘์„ฑ์ž์™€ ๋‹ค์ˆ˜์˜ ์ฝ๊ธฐ์ž๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

Primary ์„œ๋ฒ„๋Š” ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ํฌํ•จํ•˜๋Š” ๋งˆ์šดํŠธ๋œ ๋ณผ๋ฅจ์ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋ฐฐํฌ ๊ด€์ ์—์„œ ๋ณด๋ฉด, imap.forwardemail.net ๋’ค์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐœ๋ณ„ IMAP ์„œ๋ฒ„๋ฅผ ๋ณด์กฐ ์„œ๋ฒ„("Secondary")๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์€ WebSockets๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค:

  • Primary ์„œ๋ฒ„๋Š” ws์˜ WebSocketServer ์„œ๋ฒ„ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Secondary ์„œ๋ฒ„๋Š” ws์˜ WebSocket ํด๋ผ์ด์–ธํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๋Š” websocket-as-promised์™€ reconnecting-websocket์œผ๋กœ ๋ž˜ํ•‘๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ๋ž˜ํผ๋Š” WebSocket์ด ์žฌ์—ฐ๊ฒฐ๋˜๊ณ  ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์†ก์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

๋ฐฑ์—…

์š”์•ฝ; ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผ๋ฐ•์Šค์˜ ๋ฐฑ์—…์€ ๋งค์ผ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์–ธ์ œ๋“ ์ง€ ๋‚ด ๊ณ„์ • ๋„๋ฉ”์ธ ๋ณ„์นญ์—์„œ ์ฆ‰์‹œ ์ƒˆ ๋ฐฑ์—…์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ์ตœ์‹  ๋ฐฑ์—…์„ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—…์„ ์œ„ํ•ด, IMAP ๋ช…๋ น ์ฒ˜๋ฆฌ ์ค‘ ๋งค์ผ SQLite VACUUM INTO ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉฐ, ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋‚ด IMAP ์—ฐ๊ฒฐ์—์„œ ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ๋ฐฑ์—…์ด ์—†๊ฑฐ๋‚˜ ํŒŒ์ผ์˜ SHA-256 ํ•ด์‹œ๊ฐ€ ๊ฐ€์žฅ ์ตœ๊ทผ ๋ฐฑ์—…๊ณผ ๋น„๊ตํ•ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๋ฐฑ์—…์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

backup ๋‚ด์žฅ ๋ช…๋ น ๋Œ€์‹  VACUUM INTO ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”, backup ๋ช…๋ น ์‹คํ–‰ ์ค‘ ํŽ˜์ด์ง€๊ฐ€ ์ˆ˜์ •๋˜๋ฉด ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. VACUUM INTO ๋ช…๋ น์€ ์Šค๋ƒ…์ƒท์„ ์ฐ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ GitHub ๋ฐ Hacker News์˜ ๋Œ“๊ธ€์„ ์ฐธ์กฐํ•˜์„ธ์š”.

๋˜ํ•œ backup ๋ช…๋ น์€ rekey๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๊นŒ์ง€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ž ์‹œ ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋‚จ๊ธฐ ๋•Œ๋ฌธ์— VACUUM INTO๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ด GitHub ๋Œ“๊ธ€ ์ฐธ์กฐ).

Secondary๋Š” WebSocket ์—ฐ๊ฒฐ์„ ํ†ตํ•ด Primary์— ๋ฐฑ์—… ์‹คํ–‰์„ ์ง€์‹œํ•˜๋ฉฐ, Primary๋Š” ๋ช…๋ น์„ ์ˆ˜์‹ ํ•œ ํ›„ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  1. ์•”ํ˜ธํ™”๋œ ๋ฉ”์ผ๋ฐ•์Šค์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  2. ์“ฐ๊ธฐ ์ž ๊ธˆ์„ ํš๋“ํ•ฉ๋‹ˆ๋‹ค.
  3. wal_checkpoint(PASSIVE)๋ฅผ ํ†ตํ•ด WAL ์ฒดํฌํฌ์ธํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. SQLite VACUUM INTO ๋ช…๋ น์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ณต์‚ฌ๋œ ํŒŒ์ผ์ด ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์—ด๋ฆฌ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(์•ˆ์ „์žฅ์น˜/๋”๋ฏธ ๋ฐฉ์ง€).
  6. ์ด๋ฅผ Cloudflare R2์— ์—…๋กœ๋“œํ•˜์—ฌ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์ง€์ •๋œ ๊ฒฝ์šฐ ์ž์ฒด ์ œ๊ณต์ž์—๊ฒŒ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

๋ฉ”์ผ๋ฐ•์Šค๋Š” ์•”ํ˜ธํ™”๋˜์–ด ์žˆ๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์„ธ์š” โ€“ WebSocket ํ†ต์‹ ์— ๋Œ€ํ•ด IP ์ œํ•œ ๋ฐ ๊ธฐํƒ€ ์ธ์ฆ ์กฐ์น˜๋ฅผ ์ ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ โ€“ ์•…์˜์ ์ธ ํ–‰์œ„์ž๊ฐ€ ์žˆ๋”๋ผ๋„ WebSocket ํŽ˜์ด๋กœ๋“œ์— IMAP ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์—ด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ๋Š” ๋ฉ”์ผ๋ฐ•์Šค๋‹น ๋ฐฑ์—…์ด ํ•˜๋‚˜๋งŒ ์ €์žฅ๋˜์ง€๋งŒ, ์•ž์œผ๋กœ๋Š” ์‹œ์  ๋ณต๊ตฌ("PITR")๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ IMAP ์„œ๋ฒ„๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ, ์ •๊ทœ ํ‘œํ˜„์‹ ๋“ฑ์„ ์ง€์›ํ•˜๋Š” SEARCH ๋ช…๋ น์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋น ๋ฅธ ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์€ FTS5์™€ sqlite-regex ๋•๋ถ„์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” SQLite ๋ฉ”์ผ๋ฐ•์Šค์— Date ๊ฐ’์„ ISO 8601 ๋ฌธ์ž์—ด๋กœ ์ €์žฅํ•˜๋ฉฐ, ์ด๋Š” Date.prototype.toISOString (UTC ํƒ€์ž„์กด ์‚ฌ์šฉ) ์„ ํ†ตํ•ด ๋™๋“ฑ์„ฑ ๋น„๊ต๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ์— ํฌํ•จ๋œ ๋ชจ๋“  ์†์„ฑ์— ๋Œ€ํ•ด ์ธ๋ฑ์Šค๋„ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ

๋‹ค์Œ์€ ์†Œ์Šค ์ฝ”๋“œ ๋ฐ ๊ฐœ๋ฐœ ํ”„๋กœ์„ธ์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์•ŒํŒŒ๋ฒณ์ˆœ์œผ๋กœ ์ •๋ฆฌํ•œ ํ‘œ์ž…๋‹ˆ๋‹ค:

ํ”„๋กœ์ ํŠธ ๋ชฉ์ 
Ansible ์ „์ฒด ์„œ๋ฒ„ ๊ตฐ์„ ์‰ฝ๊ฒŒ ์œ ์ง€, ํ™•์žฅ ๋ฐ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ DevOps ์ž๋™ํ™” ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.
Bree cron, ๋‚ ์งœ, ms, later, ๊ทธ๋ฆฌ๊ณ  ์‚ฌ๋žŒ์ด ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์ง€์›์„ ์ œ๊ณตํ•˜๋Š” Node.js ๋ฐ JavaScript์šฉ ์ž‘์—… ์Šค์ผ€์ค„๋Ÿฌ์ž…๋‹ˆ๋‹ค.
Cabin ๋ณด์•ˆ๊ณผ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ๋ฅผ ๊ณ ๋ คํ•œ ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ธ JavaScript ๋ฐ Node.js ๋กœ๊น… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.
Lad MVC ๋“ฑ์œผ๋กœ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜์™€ ์—”์ง€๋‹ˆ์–ด๋ง ์„ค๊ณ„๋ฅผ ์ง€์›ํ•˜๋Š” Node.js ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.
MongoDB ๋ฉ”์ผ๋ฐ•์Šค ์™ธ์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค(์˜ˆ: ๊ณ„์ •, ์„ค์ •, ๋„๋ฉ”์ธ, ๋ณ„์นญ ๊ตฌ์„ฑ).
Mongoose ์ „์ฒด ์Šคํƒ์—์„œ ์‚ฌ์šฉํ•˜๋Š” MongoDB ๊ฐ์ฒด ๋ฌธ์„œ ๋ชจ๋ธ๋ง("ODM")์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” SQLite์™€ ํ•จ๊ป˜ Mongoose๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํŠน๋ณ„ํ•œ ํ—ฌํผ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค ๐ŸŽ‰
Node.js ๋ชจ๋“  ์„œ๋ฒ„ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ํฌ๋กœ์Šค ํ”Œ๋žซํผ JavaScript ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค.
Nodemailer ์ด๋ฉ”์ผ ์ „์†ก, ์—ฐ๊ฒฐ ์ƒ์„ฑ ๋“ฑ์„ ์œ„ํ•œ Node.js ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ํ”„๋กœ์ ํŠธ์˜ ๊ณต์‹ ํ›„์›์ž์ž…๋‹ˆ๋‹ค.
Redis ์บ์‹ฑ, ๋ฐœํ–‰/๊ตฌ๋… ์ฑ„๋„, DNS over HTTPS ์š”์ฒญ์„ ์œ„ํ•œ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ž…๋‹ˆ๋‹ค.
SQLite3MultipleCiphers ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒŒ์ผ(์“ฐ๊ธฐ ์•ž์„œ ๊ธฐ๋ก("WAL"), ์ €๋„, ๋กค๋ฐฑ ๋“ฑ ํฌํ•จ)์„ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ๋Š” SQLite ์•”ํ˜ธํ™” ํ™•์žฅ์ž…๋‹ˆ๋‹ค.
SQLiteStudio ๊ฐœ๋ฐœ์šฉ ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ํ…Œ์ŠคํŠธ, ๋‹ค์šด๋กœ๋“œ, ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ์  SQLite ํŽธ์ง‘๊ธฐ(์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค).
SQLite ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๊ณ  ๋…๋ฆฝ์ ์ด๋ฉฐ ๋น ๋ฅด๊ณ  ๊ฒฌ๊ณ ํ•œ IMAP ์ €์žฅ์„ ์œ„ํ•œ ์ž„๋ฒ ๋””๋“œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ณ„์ธต์ž…๋‹ˆ๋‹ค.
Spam Scanner Node.js ๊ธฐ๋ฐ˜ ์ŠคํŒธ ๋ฐฉ์ง€, ์ด๋ฉ”์ผ ํ•„ํ„ฐ๋ง ๋ฐ ํ”ผ์‹ฑ ๋ฐฉ์ง€ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค (Spam Assassin ๋ฐ rspamd ๋Œ€์ฒดํ’ˆ).
Tangerine Node.js์™€ Redis ์บ์‹ฑ์„ ์‚ฌ์šฉํ•œ DNS over HTTPS ์š”์ฒญ์œผ๋กœ ์ „ ์„ธ๊ณ„ ์ผ๊ด€์„ฑ๊ณผ ๊ทธ ์ด์ƒ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
Thunderbird ์šฐ๋ฆฌ ๊ฐœ๋ฐœํŒ€์ด ์‚ฌ์šฉํ•˜๋ฉฐ Forward Email๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๋Š” ์„ ํ˜ธ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ์ž…๋‹ˆ๋‹ค.
UTM iOS ๋ฐ macOS์šฉ ๊ฐ€์ƒ ๋จธ์‹ ์„ ์ƒ์„ฑํ•˜์—ฌ IMAP ๋ฐ SMTP ์„œ๋ฒ„์™€ ํ•จ๊ป˜ ๋‹ค์–‘ํ•œ ์ด๋ฉ”์ผ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋ณ‘๋ ฌ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœํŒ€ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.
Ubuntu ๋ชจ๋“  ์ธํ”„๋ผ๋ฅผ ๊ตฌ๋™ํ•˜๋Š” ํ˜„๋Œ€์ ์ธ ์˜คํ”ˆ ์†Œ์Šค Linux ๊ธฐ๋ฐ˜ ์„œ๋ฒ„ ์šด์˜ ์ฒด์ œ์ž…๋‹ˆ๋‹ค.
WildDuck IMAP ์„œ๋ฒ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค โ€“ ์ฒจ๋ถ€ ํŒŒ์ผ ์ค‘๋ณต ์ œ๊ฑฐ ๋ฐ IMAP ํ”„๋กœํ† ์ฝœ ์ง€์› ์ฐธ๊ณ ํ•˜์„ธ์š”.
better-sqlite3-multiple-ciphers SQLite3์™€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋น ๋ฅด๊ณ  ๊ฐ„๋‹จํ•œ Node.js API ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.
email-templates ๋งž์ถค ์ด๋ฉ”์ผ(์˜ˆ: ๊ณ„์ • ์•Œ๋ฆผ ๋“ฑ)์„ ์ƒ์„ฑ, ๋ฏธ๋ฆฌ๋ณด๊ธฐ, ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ธ ์ด๋ฉ”์ผ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.
json-sql-enhanced Mongo ์Šคํƒ€์ผ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” SQL ์ฟผ๋ฆฌ ๋นŒ๋”์ž…๋‹ˆ๋‹ค. ์ „์ฒด ์Šคํƒ์—์„œ Mongo ์Šคํƒ€์ผ๋กœ ๊ณ„์† ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด ๊ฐœ๋ฐœํŒ€์˜ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•˜๋ฉฐ, ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด SQL ์ธ์ ์…˜ ๊ณต๊ฒฉ๋„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
knex-schema-inspector ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” SQL ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ธ๋ฑ์Šค, ํ…Œ์ด๋ธ”, ์ปฌ๋Ÿผ, ์ œ์•ฝ ์กฐ๊ฑด ๋“ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ณ  1:1๋กœ ์ผ์น˜ํ•˜๋Š”์ง€ ์‰ฝ๊ฒŒ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ ์‹œ ์ƒˆ ์ปฌ๋Ÿผ๊ณผ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ž๋™ํ™” ํ—ฌํผ๋„ ์ž‘์„ฑํ–ˆ์œผ๋ฉฐ, ๋งค์šฐ ์ƒ์„ธํ•œ ์˜ค๋ฅ˜ ์•Œ๋ฆผ๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
knex ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๊ณผ knex-schema-inspector๋ฅผ ํ†ตํ•œ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” SQL ์ฟผ๋ฆฌ ๋นŒ๋”์ž…๋‹ˆ๋‹ค.
mandarin Google Cloud Translation API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Markdown ์ง€์›๊ณผ ํ•จ๊ป˜ ์ž๋™ i18n ๊ตฌ๋ฌธ ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
mx-connect MX ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์„ ํ•ด๊ฒฐํ•˜๊ณ  ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” Node.js ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค.
pm2 ๋‚ด์žฅ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๊ฐ€ ํฌํ•จ๋œ Node.js ํ”„๋กœ๋•์…˜ ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ์ž์ž…๋‹ˆ๋‹ค (์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋ฏธ์„ธ ์กฐ์ •๋จ).
smtp-server SMTP ์„œ๋ฒ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ๋ฉ”์ผ ๊ตํ™˜("MX") ๋ฐ ์•„์›ƒ๋ฐ”์šด๋“œ SMTP ์„œ๋ฒ„์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
ImapTest IMAP ์„œ๋ฒ„๋ฅผ ๋ฒค์น˜๋งˆํฌ ๋ฐ RFC ๋ช…์„ธ IMAP ํ”„๋กœํ† ์ฝœ ํ˜ธํ™˜์„ฑ์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธํ•˜๋Š” ์œ ์šฉํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋Š” Dovecot ํŒ€์ด ๋งŒ๋“ค์—ˆ์œผ๋ฉฐ(2002๋…„ 7์›”๋ถ€ํ„ฐ ํ™œ๋ฐœํ•œ ์˜คํ”ˆ ์†Œ์Šค IMAP ๋ฐ POP3 ์„œ๋ฒ„), ์šฐ๋ฆฌ๋Š” ์ด ๋„๊ตฌ๋กœ IMAP ์„œ๋ฒ„๋ฅผ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ GitHub ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ๋“ค์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Providers

Provider Purpose
Cloudflare DNS ์ œ๊ณต์ž, ์ƒํƒœ ๊ฒ€์‚ฌ, ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ, ๊ทธ๋ฆฌ๊ณ  Cloudflare R2๋ฅผ ์ด์šฉํ•œ ๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€.
GitHub ์†Œ์Šค ์ฝ”๋“œ ํ˜ธ์ŠคํŒ…, CI/CD, ๊ทธ๋ฆฌ๊ณ  ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ.
Digital Ocean ์ „์šฉ ์„œ๋ฒ„ ํ˜ธ์ŠคํŒ… ๋ฐ ๊ด€๋ฆฌํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค.
Vultr ์ „์šฉ ์„œ๋ฒ„ ํ˜ธ์ŠคํŒ….
DataPacket ์ „์šฉ ์„œ๋ฒ„ ํ˜ธ์ŠคํŒ….

Thoughts

Principles

Forward Email์€ ๋‹ค์Œ ์›์น™์— ๋”ฐ๋ผ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  1. ํ•ญ์ƒ ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ด๊ณ , ๋ณด์•ˆ ๋ฐ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ์— ์ค‘์ ์„ ๋‘๋ฉฐ, ํˆฌ๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, ์˜ค์ปด์˜ ๋ฉด๋„๋‚ , ๊ทธ๋ฆฌ๊ณ  ๋„๊ทธํ‘ธ๋”ฉ์„ ์ค€์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ž๊ธˆ์ด ๋ถ€์กฑํ•œ, ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๋ฐฉ์‹์œผ๋กœ ์šด์˜๋˜๋Š”, ๊ทธ๋ฆฌ๊ณ  ๋ผ๋ฉด ์ˆ˜์ต์„ฑ์ด ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

Experiments

์š”์•ฝ; ๊ถ๊ทน์ ์œผ๋กœ S3 ํ˜ธํ™˜ ๊ฐ์ฒด ์Šคํ† ๋ฆฌ์ง€ ๋ฐ/๋˜๋Š” Virtual Tables ์‚ฌ์šฉ์€ ์„ฑ๋Šฅ ๋ฌธ์ œ๋กœ ๊ธฐ์ˆ ์ ์œผ๋กœ ์‹คํ˜„ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์œผ๋กœ ์ธํ•ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์œ„์—์„œ ๋…ผ์˜ํ•œ ์ตœ์ข… SQLite ์†”๋ฃจ์…˜์— ๋„๋‹ฌํ•˜๊ธฐ๊นŒ์ง€ ๋ช‡ ๊ฐ€์ง€ ์‹คํ—˜์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” rclone๊ณผ SQLite๋ฅผ S3 ํ˜ธํ™˜ ์Šคํ† ๋ฆฌ์ง€ ๊ณ„์ธต๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์‹œ๋„์˜€์Šต๋‹ˆ๋‹ค.

์ด ์‹คํ—˜์„ ํ†ตํ•ด rclone, SQLite, ๊ทธ๋ฆฌ๊ณ  VFS ์‚ฌ์šฉ๊ณผ ๊ด€๋ จ๋œ ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ๋” ์ž˜ ์ดํ•ดํ•˜๊ณ  ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค:

  • rclone์—์„œ --vfs-cache-mode writes ํ”Œ๋ž˜๊ทธ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ฉด ์ฝ๊ธฐ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ์“ฐ๊ธฐ๋Š” ์บ์‹œ๋ฉ๋‹ˆ๋‹ค.
    • ์ „ ์„ธ๊ณ„์— ๋ถ„์‚ฐ๋œ ์—ฌ๋Ÿฌ IMAP ์„œ๋ฒ„๊ฐ€ ์žˆ๋‹ค๋ฉด, ๋‹จ์ผ ์ž‘์„ฑ์ž์™€ ๋‹ค์ˆ˜์˜ ์ฒญ์ทจ์ž(์˜ˆ: pub/sub ๋ฐฉ์‹)๊ฐ€ ์•„๋‹Œ ์ด์ƒ ์บ์‹œ๋Š” ์„œ๋ฒ„ ๊ฐ„์— ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ์ด๋Š” ๋งค์šฐ ๋ณต์žกํ•˜๋ฉฐ, ์ด๋Ÿฐ ๋ณต์žก์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹จ์ผ ์‹คํŒจ ์ง€์ ์ด ๋” ๋งŽ์ด ์ƒ๊น๋‹ˆ๋‹ค.
    • S3 ํ˜ธํ™˜ ์Šคํ† ๋ฆฌ์ง€ ์ œ๊ณต์ž๋Š” ๋ถ€๋ถ„ ํŒŒ์ผ ๋ณ€๊ฒฝ์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ .sqlite ํŒŒ์ผ์˜ ์–ด๋–ค ๋ณ€๊ฒฝ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ „์ฒด ๋ณ€๊ฒฝ ๋ฐ ์žฌ์—…๋กœ๋“œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
    • rsync ๊ฐ™์€ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜๋„ ์žˆ์ง€๋งŒ, ์“ฐ๊ธฐ ์•ž์„œ ๋กœ๊ทธ("WAL") ์ง€์›์— ์ดˆ์ ์ด ๋งž์ถฐ์ ธ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” Litestream์„ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ์šฐ๋ฆฌ์˜ ์•”ํ˜ธํ™” ์‚ฌ์šฉ์€ ์ด๋ฏธ WAL ํŒŒ์ผ์„ ์•”ํ˜ธํ™”ํ•˜๋ฏ€๋กœ Litestream์— ์˜์กดํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง Litestream์„ ํ”„๋กœ๋•์…˜์— ์ž์‹  ์žˆ๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ๋ถ€์กฑํ•˜๋ฉฐ ์•„๋ž˜์— ๋ช‡ ๊ฐ€์ง€ ๋ฉ”๋ชจ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
    • --vfs-cache-mode writes ์˜ต์…˜(์“ฐ๊ธฐ์šฉ์œผ๋กœ rclone ์œ„์—์„œ SQLite๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•)์„ ์‚ฌ์šฉํ•˜๋ฉด ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณต์‚ฌํ•˜๋ ค ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. 10GB์งœ๋ฆฌ ๋ฉ”์ผ๋ฐ•์Šค ํ•˜๋‚˜๋Š” ๊ดœ์ฐฎ์ง€๋งŒ, ๋งค์šฐ ํฐ ์—ฌ๋Ÿฌ ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉด IMAP ์„œ๋ฒ„๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ๊ณผ ENOMEM ์˜ค๋ฅ˜, ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ์˜ค๋ฅ˜, ๋ฐ์ดํ„ฐ ์†์ƒ์— ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค.
  • SQLite Virtual Tables(์˜ˆ: s3db ์‚ฌ์šฉ)๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ S3 ํ˜ธํ™˜ ์Šคํ† ๋ฆฌ์ง€ ๊ณ„์ธต์— ๋‘๋ ค ํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:
    • ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ๊ฐ€ ๋งค์šฐ ๋А๋ฆฝ๋‹ˆ๋‹ค. S3 API ์—”๋“œํฌ์ธํŠธ์— HTTP GET, PUT, HEAD, POST ์š”์ฒญ์„ ๊ณ„์† ๋ณด๋‚ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
    • ๊ฐœ๋ฐœ ํ…Œ์ŠคํŠธ์—์„œ 500K-1M+ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ๊ด‘์„ฌ์œ  ์ธํ„ฐ๋„ท์—์„œ๋„ S3 ํ˜ธํ™˜ ์ œ๊ณต์ž์— ์“ฐ๊ธฐ ๋ฐ ์ฝ๊ธฐ ์ฒ˜๋ฆฌ๋Ÿ‰์— ์˜ํ•ด ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐœ๋ฐœ์ž๋“ค์ด ์ˆœ์ฐจ์  SQL INSERT ๋ฌธ๊ณผ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ๋ฅผ for ๋ฃจํ”„๋กœ ์‹คํ–‰ํ–ˆ๋Š”๋ฐ, ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ ์„ฑ๋Šฅ์ด ๋งค์šฐ ๋А๋ ธ์Šต๋‹ˆ๋‹ค.
    • ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์€ ์ธ๋ฑ์Šค, ALTER TABLE ๋ฌธ, ๊ทธ๋ฆฌ๊ณ  ๊ธฐํƒ€ ์ œํ•œ์‚ฌํ•ญ์ด ์žˆ์–ด ๋ฐ์ดํ„ฐ ์–‘์— ๋”ฐ๋ผ 1-2๋ถ„ ์ด์ƒ ์ง€์—ฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๊ฐ์ฒด๋Š” ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ์ €์žฅ๋˜๋ฉฐ, ๊ธฐ๋ณธ ์•”ํ˜ธํ™” ์ง€์›์ด ์—†์Šต๋‹ˆ๋‹ค.
  • sqlite-s3vfs๋„ ๋น„์Šทํ•œ ๊ฐœ๋…๊ณผ ๊ธฐ์ˆ ์  ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๊ฒช์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅ์„ฑ์œผ๋กœ๋Š” wxSQLite3 ๊ฐ™์€ ์•”ํ˜ธํ™”๊ฐ€ ํฌํ•จ๋œ ์ปค์Šคํ…€ sqlite3 ๋นŒ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, ์ด๋Š” ์„ค์ • ํŒŒ์ผ ํŽธ์ง‘์„ ํ†ตํ•ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค(์šฐ๋ฆฌ๊ฐ€ ์œ„ ์†”๋ฃจ์…˜์—์„œ ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘).
  • ๋˜ ๋‹ค๋ฅธ ์ ‘๊ทผ๋ฒ•์€ multiplex ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, 32GB ์ œํ•œ์ด ์žˆ๊ณ  ๋ณต์žกํ•œ ๋นŒ๋“œ ๋ฐ ๊ฐœ๋ฐœ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.
  • ALTER TABLE ๋ฌธ์ด ํ•„์š”ํ•˜๋ฏ€๋กœ(๊ฐ€์ƒ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ ๋ถˆ๊ฐ€) knex-schema-inspector์™€์˜ ํ›…์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ ์†์ƒ์„ ๋ฐฉ์ง€ํ•˜๊ณ , mongoose ์Šคํ‚ค๋งˆ ์ •์˜์— ๋”ฐ๋ฅธ ์œ ํšจํ•œ ๋ฌธ์„œ๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ ํ–‰์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค(์ œ์•ฝ์กฐ๊ฑด, ๋ณ€์ˆ˜ ํƒ€์ž…, ์ž„์˜ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ ํฌํ•จ).
  • ์˜คํ”ˆ์†Œ์Šค ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ SQLite ๊ด€๋ จ S3 ํ˜ธํ™˜ ํ”„๋กœ์ ํŠธ๋Š” ๊ฑฐ์˜ Python ๊ธฐ๋ฐ˜์ด๋ฉฐ, ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” 100% JavaScript ์Šคํƒ๊ณผ๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
  • sqlite-zstd ๊ฐ™์€ ์••์ถ• ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์œ ๋งํ•ด ๋ณด์ด๋‚˜, ์•„์ง ํ”„๋กœ๋•์…˜ ์‚ฌ์šฉ ์ค€๋น„๊ฐ€ ์•ˆ ๋œ ๋“ฏํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  String, Object, Map, Array, Set, Buffer ๊ฐ™์€ ๋ฐ์ดํ„ฐ ํƒ€์ž…์— ๋Œ€ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธก ์••์ถ•์ด ๋” ๊น”๋”ํ•˜๊ณ  ์‰ฌ์šด ์ ‘๊ทผ๋ฒ•์ด๋ฉฐ, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋„ ์‰ฝ์Šต๋‹ˆ๋‹ค(์˜ˆ: Boolean ํ”Œ๋ž˜๊ทธ๋‚˜ ์ปฌ๋Ÿผ ์ €์žฅ, ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋กœ PRAGMA user_version=1 ์••์ถ•, user_version=0 ๋น„์••์ถ• ์‚ฌ์šฉ).
    • ๋‹คํ–‰ํžˆ IMAP ์„œ๋ฒ„ ์Šคํ† ๋ฆฌ์ง€์— ์ฒจ๋ถ€ํŒŒ์ผ ์ค‘๋ณต ์ œ๊ฑฐ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด, ๋™์ผ ์ฒจ๋ถ€ํŒŒ์ผ์ด ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€์— ์ค‘๋ณต ์ €์žฅ๋˜์ง€ ์•Š๊ณ , ํ•˜๋‚˜์˜ ์ฒจ๋ถ€ํŒŒ์ผ์ด ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€์™€ ์Šค๋ ˆ๋“œ์—์„œ ์ฐธ์กฐ๋ฉ๋‹ˆ๋‹ค.
  • SQLite ๋ณต์ œ ๋ฐ ๋ฐฑ์—… ์†”๋ฃจ์…˜์ธ Litestream ํ”„๋กœ์ ํŠธ๋Š” ๋งค์šฐ ์œ ๋งํ•˜๋ฉฐ, ์•ž์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค.
    • ์ €์ž๋“ค์„ ํ„ํ•˜ํ•˜๋ ค๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, 10๋…„ ๋„˜๊ฒŒ ์˜คํ”ˆ์†Œ์Šค์— ๊ธฐ์—ฌํ•œ ๊ทธ๋“ค์˜ ์ž‘์—…์„ ์กด๊ฒฝํ•˜์ง€๋งŒ, ์‹ค์ œ ์‚ฌ์šฉ์—์„œ๋Š” ๋งŽ์€ ๋ฌธ์ œ์™€ ๋ฐ์ดํ„ฐ ์†์‹ค ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.
  • ๋ฐฑ์—… ๋ณต์›์€ ๋งˆ์ฐฐ ์—†์ด ๊ฐ„๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. MongoDB์˜ mongodump์™€ mongoexport ๊ฐ™์€ ์†”๋ฃจ์…˜์€ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆฌ๋ฉฐ ์„ค์ •์ด ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.
    • SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋‹จ์ผ ํŒŒ์ผ์ด๋ผ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ ์–ธ์ œ๋“ ์ง€ ๋ฉ”์ผ๋ฐ•์Šค๋ฅผ ๊ฐ€์ ธ๊ฐ€๊ณ  ๋– ๋‚  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.
      • ๊ฐ„๋‹จํ•œ Node.js ๋ช…๋ น์–ด fs.unlink('mailbox.sqlite')๋กœ ๋””์Šคํฌ ์ €์žฅ์†Œ์—์„œ ์˜๊ตฌ ์‚ญ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
      • S3 ํ˜ธํ™˜ API์˜ HTTP DELETE๋ฅผ ์‚ฌ์šฉํ•ด ์Šค๋ƒ…์ƒท๊ณผ ๋ฐฑ์—…์„ ์‰ฝ๊ฒŒ ์ œ๊ฑฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
    • SQLite๊ฐ€ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ๋น ๋ฅด๋ฉฐ ๋น„์šฉ ํšจ์œจ์ ์ธ ์†”๋ฃจ์…˜์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์•ˆ์˜ ๋ถ€์žฌ

์ €ํฌ๊ฐ€ ์•„๋Š” ํ•œ, ๋‹ค๋ฅธ ์ด๋ฉ”์ผ ์„œ๋น„์Šค๋“ค์€ ์ด์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์˜คํ”ˆ ์†Œ์Šค๋„ ์•„๋‹™๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ธฐ์กด ์ด๋ฉ”์ผ ์„œ๋น„์Šค๋“ค์ด ์ŠคํŒŒ๊ฒŒํ‹ฐ ์ฝ”๋“œ ๐Ÿ ๊ฐ€ ํฌํ•จ๋œ ๋ ˆ๊ฑฐ์‹œ ๊ธฐ์ˆ ์„ ์šด์˜ ์ค‘์ด๊ธฐ ๋•Œ๋ฌธ์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์กด ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์ œ๊ณต์—…์ฒด ๋Œ€๋ถ€๋ถ„์€ ํ์‡„ ์†Œ์Šค์ด๊ฑฐ๋‚˜ ์˜คํ”ˆ ์†Œ์Šค๋ผ๊ณ  ๊ด‘๊ณ ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ํ”„๋ก ํŠธ์—”๋“œ๋งŒ ์˜คํ”ˆ ์†Œ์Šค์ž…๋‹ˆ๋‹ค.

์ด๋ฉ”์ผ์—์„œ ๊ฐ€์žฅ ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„(์‹ค์ œ ์ €์žฅ/IMAP/SMTP ์ƒํ˜ธ์ž‘์šฉ)์€ ๋ชจ๋‘ ๋ฐฑ์—”๋“œ(์„œ๋ฒ„)์—์„œ ์ฒ˜๋ฆฌ๋˜๋ฉฐ, ํ”„๋ก ํŠธ์—”๋“œ(ํด๋ผ์ด์–ธํŠธ)์—์„œ๋Š” ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Forward Email ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

์˜ค๋Š˜ https://forwardemail.net ์—์„œ ๊ฐ€์ž…ํ•˜์„ธ์š”! ๐Ÿš€