Kuantum Dirençli E-posta: E-postanızı güvende tutmak için şifreli SQLite posta kutularını nasıl kullanıyoruz?

Önsöz

Important

E-posta hizmetimiz %100 açık kaynaklı olup, güvenli ve şifreli SQLite posta kutuları aracılığıyla gizlilik odaklıdır.

IMAP desteği'ı piyasaya sürene kadar kalıcı veri depolama ihtiyaçlarımız için MongoDB'yi kullanıyorduk.

Bu teknoloji harika ve biz bunu bugün hala kullanıyoruz; ancak MongoDB ile beklemede şifreleme özelliğinden yararlanmak için Digital Ocean veya Mongo Atlas gibi MongoDB Enterprise sunan bir sağlayıcı kullanmanız veya bir kurumsal lisans için ödeme yapmanız (ve sonrasında satış ekibinin gecikmesiyle uğraşmanız) gerekiyor.

E-postayı İlet ekibimiz, IMAP posta kutuları için geliştirici dostu, ölçeklenebilir, güvenilir ve şifreli bir depolama çözümüne ihtiyaç duyuyordu. Açık kaynaklı geliştiriciler olarak, bekleme durumunda şifreleme özelliğini kullanmak için lisans ücreti ödemeniz gereken bir teknolojiyi kullanmak ilkelerimiz'in beklentilerini karşılamıyordu; bu yüzden bu ihtiyaçları karşılamak için deneyler yaptık, araştırmalar yaptık ve sıfırdan yeni bir çözüm geliştirdik.

Posta kutularınızı paylaşmak için ortak bir veritabanı kullanmak yerine, posta kutularınızı ayrı ayrı saklıyor ve şifrenizle (ki bu şifre yalnızca sizdedir) şifreliyoruz. E-posta hizmetimiz o kadar güvenlidir ki, şifrenizi unutursanız posta kutunuzu kaybedersiniz (ve çevrimdışı yedeklemelerle kurtarmanız veya baştan başlamanız gerekir).

Aşağıda e-posta servis sağlayıcılarının karşılaştırılması, hizmetimiz nasıl çalışır, teknoloji yığınımız ve daha fazlasıyla ilgili derinlemesine incelememizi okumaya devam edin.

E-posta servis sağlayıcı karşılaştırması

Bireysel olarak şifrelenmiş SQLite posta kutularını depolayan, sınırsız alan adı, takma ad ve kullanıcı sunan ve giden SMTP, IMAP ve POP3 desteği sağlayan %100 açık kaynaklı ve gizliliğe odaklı tek e-posta servis sağlayıcısıyız:

Diğer e-posta sağlayıcılarının aksine, Forward Email ile alan adı veya takma ad bazında depolama ücreti ödemenize gerek yoktur. Depolama, tüm hesabınızda paylaşılır; yani birden fazla özel alan adınız ve her birinde birden fazla takma adınız varsa, sizin için mükemmel bir çözüm olabiliriz. Dilerseniz alan adı veya takma ad bazında depolama sınırlamaları uygulayabileceğinizi unutmayın.

E-posta Hizmeti Karşılaştırmasını Okuyun

Nasıl çalışır?

  1. Apple Mail, Thunderbird, Gmail veya Outlook gibi e-posta istemcinizi kullanarak, kullanıcı adınızı ve şifrenizi kullanarak güvenli IMAP sunucularımıza bağlanın:
  • Kullanıcı adınız, hello@example.com gibi alan adınızdaki tam takma adınızdır.
  • Şifreniz rastgele oluşturulur ve yalnızca Hesabım Alan Adlarım Takma Adlarım'dan Şifre Oluştur'a tıkladığınızda 30 saniye boyunca görüntülenir.
  1. Bağlandıktan sonra, e-posta istemciniz posta kutunuzu senkronize tutmak için IMAP protokol komutları adresini IMAP sunucumuza gönderecektir. Bu, taslak e-postaları yazmayı ve depolamayı ve yapabileceğiniz diğer işlemleri (örneğin, bir e-postayı Önemli olarak etiketlemek veya Spam/İstenmeyen Posta olarak işaretlemek) içerir.

  2. Posta değişim sunucuları (genellikle "MX" sunucuları olarak bilinir), gelen yeni e-postaları alır ve posta kutunuza depolar. Bu durum gerçekleştiğinde, e-posta istemciniz bilgilendirilir ve posta kutunuzu senkronize eder. Posta değişim sunucularımız, e-postalarınızı bir veya daha fazla alıcıya (web kancaları dahil) iletebilir, e-postalarınızı şifreli IMAP depolama alanınızda depolayabilir veya veya her ikisini de yapabilir!

Tip

Daha fazla bilgi edinmek ister misiniz? e-posta yönlendirme nasıl kurulur, posta değişim servisimiz nasıl çalışır'i okuyun veya rehberlerimiz'yi görüntüleyin.

  1. Perde arkasında, güvenli e-posta depolama tasarımımız posta kutularınızı şifrelenmiş ve yalnızca sizin tarafınızdan erişilebilir tutmak için iki şekilde çalışır:
  • Bir göndericiden sizin adınıza yeni bir e-posta alındığında, posta değişim sunucularımız sizin adınıza özel, geçici ve şifrelenmiş bir posta kutusuna yazar.

  • E-posta istemcinizle IMAP sunucumuza bağlandığınızda, parolanız bellekte şifrelenir ve posta kutunuza okumak ve yazmak için kullanılır. Posta kutunuz yalnızca bu parola ile okunabilir ve yazılabilir. Bu parolaya sahip tek kişi siz olduğunuz için, posta kutunuza erişirken yalnızca siz okuyabilir ve yazabilirsiniz. E-posta istemciniz bir sonraki e-posta sorgulama veya senkronizasyon girişiminde bulunduğunda, yeni iletileriniz bu geçici posta kutusundan aktarılacak ve verdiğiniz parola kullanılarak gerçek posta kutusu dosyanızda saklanacaktır. Bu geçici posta kutusunun daha sonra temizlenip silineceğini ve iletilerin yalnızca parola korumalı posta kutunuzda saklanacağını unutmayın.

  • IMAP'ye bağlıysanız (örneğin, Apple Mail veya Thunderbird gibi bir e-posta istemcisi kullanıyorsanız), geçici disk depolama alanına yazmamıza gerek kalmaz. Bunun yerine, bellek içi şifrelenmiş IMAP parolanız alınır ve kullanılır. Gerçek zamanlı olarak, size bir mesaj iletilmeye çalışıldığında, tüm IMAP sunucularına sizin için etkin bir oturum olup olmadığını soran bir WebSocket isteği göndeririz (bu, alma kısmıdır) ve ardından bu şifrelenmiş bellek içi parolayı iletiriz. Bu sayede geçici bir posta kutusuna yazmamıza gerek kalmaz, şifrelenmiş parolanızı kullanarak gerçek şifrelenmiş posta kutunuza yazabiliriz.

  1. Şifrelenmiş posta kutularınızın yedekleri günlük olarak oluşturulur. İstediğiniz zaman yeni bir yedekleme talep edebilir veya en son yedeklemeyi Hesabım Alan Adları Takma Adlar bölümünden indirebilirsiniz. Başka bir e-posta hizmetine geçmeye karar verirseniz, posta kutularınızı ve yedeklerinizi istediğiniz zaman kolayca taşıyabilir, indirebilir, dışa aktarabilir ve temizleyebilirsiniz.

Teknolojileri

Veritabanları

Diğer olası veritabanı depolama katmanlarını inceledik, ancak hiçbiri SQLite kadar gereksinimlerimizi karşılamadı:

Veritabanı Beklemede şifreleme Sandboxed Posta Kutuları Lisans Used Everywhere
HÜCRE_BAĞLANTISI_0 ✅ Evet SQLite3MultipleCiphers ile :beyaz_onay_işareti: ✅ Kamu Malı :beyaz_onay_işareti:
MongoDB HÜCRE_BAĞLANTISI_0 ❌ İlişkisel veritabanı ❌ AGPL ve SSPL-1.0 :X:
rqlite HÜCRE_BAĞLANTISI_0 ❌ İlişkisel veritabanı HÜCRE_KODU_0 :X:
dqlite HÜCRE_BAĞLANTISI_0 HÜCRE_BAĞLANTISI_0 HÜCRE_KODU_0 :X:
PostgreSQL Yes ❌ İlişkisel veritabanı PostgreSQL (BSD veya MIT'ye benzer) :X:
MariaDB For InnoDB only ❌ İlişkisel veritabanı GPLv2 ve BUSL-1.1 :X:
CockroachDB HÜCRE_BAĞLANTISI_0 ❌ İlişkisel veritabanı BUSL-1.1 ve diğerleri :X:

Yukarıdaki tabloda çeşitli SQLite veritabanı depolama seçeneklerini karşılaştıran blog yazısı bulunmaktadır.

Güvenlik

Posta kutularında her zaman beklemede şifreleme (AES-256), aktarım sırasında şifreleme (TLS), HTTPS üzerinden DNS ("DoH") şifrelemesini kullanıyoruz: 🍊 mandalina ve sqleet (ChaCha20-Poly1305). Ayrıca, belirteç tabanlı iki faktörlü kimlik doğrulama (aracı saldırıları'e karşı şüpheli olan SMS'in aksine), kök erişimi devre dışı bırakılmış döndürülmüş SSH anahtarları, kısıtlı IP adresleri aracılığıyla sunuculara özel erişim ve daha fazlasını kullanıyoruz.

kötü hizmetçi saldırısı veya üçüncü taraf bir satıcıdan gelen kötü niyetli bir çalışan durumunda, posta kutunuz yalnızca oluşturduğunuz parolayla açılabilir. İçiniz rahat olsun, Cloudflare, DataPacket, Digital Ocean ve Vultr gibi SOC Tip 2 şikayet sunucu sağlayıcılarımız dışında hiçbir üçüncü taraf satıcıya güvenmiyoruz.

Amacımız mümkün olduğunca az tek bir arıza noktası olmasıdır.

Posta Kutuları

tldr; IMAP sunucularımız, posta kutularınızın her biri için ayrı ayrı şifrelenmiş SQLite veritabanları kullanır.

SQLite son derece popüler bir gömülü veritabanı – şu anda telefonunuzda ve bilgisayarınızda çalışıyor – ve neredeyse tüm büyük teknolojiler tarafından kullanılır.

Örneğin, şifrelenmiş sunucularımızda linux@example.com, info@example.com, hello@example.com vb. için bir SQLite veritabanı posta kutusu bulunur; her biri için bir .sqlite veritabanı dosyası bulunur. Veritabanı dosyalarına e-posta adreslerini de dahil etmiyoruz; bunun yerine, posta kutusunun kime ait olduğunu veya hangi e-posta adresinin altında olduğunu paylaşmayan BSON ObjectID ve benzersiz UUID'ler kullanıyoruz (örneğin, 353a03f21e534321f5d6e267.sqlite).

Bu veritabanlarının her biri, yalnızca sizin sahip olduğunuz parolanız kullanılarak (sqleet (ChaCha20-Poly1305)) şifrelenir. Bu, posta kutularınızın ayrı ayrı şifrelendiği, kendi içinde tutarlı (korumalı ve taşınabilir olduğu anlamına gelir.

SQLite'ı aşağıdaki PRAGMA ile ince ayarladık:

PRAGMA Amaç
cipher=chacha20 ChaCha20-Poly1305 SQLite database encryption. Daha fazla bilgi için Projects altındaki better-sqlite3-multiple-ciphers ifadesine bakın.
key="****************" Bu, e-posta istemcinizin IMAP bağlantısı üzerinden sunucumuza iletilen, şifresi çözülmüş, yalnızca bellekte saklanan parolanızdır. Her okuma ve yazma oturumu için yeni veritabanı örnekleri oluşturulur ve kapatılır (koruma ve izolasyonu sağlamak amacıyla).
journal_model=WAL Yazma öncesi günlüğü ("WAL") which boosts performance and allows concurrent read access.
busy_timeout=5000 Yazma kilidi hatalarını önler while other writes are taking place.
synchronous=NORMAL without data corruption risk işlemlerinin dayanıklılığını artırır.
foreign_keys=ON Yabancı anahtar referanslarının (örneğin bir tablodan diğerine ilişki) zorunlu kılınmasını sağlar. By default this is not turned on in SQLite, ancak doğrulama ve veri bütünlüğü için etkinleştirilmelidir.
encoding='UTF-8' Geliştiricinin akıl sağlığını garantilemek için kullanılacak Default encoding.

Diğer tüm varsayılanlar resmi PRAGMA belgeleri'da belirtildiği gibi SQLite'tan gelir.

Eşzamanlılık

tldr; Şifrelenmiş SQLite posta kutularınıza eş zamanlı okuma ve yazma işlemleri için WebSocket kullanıyoruz.

{#reads}'i okur

Telefonunuzdaki e-posta istemciniz imap.forwardemail.net adresini Digital Ocean IP adreslerimizden birine çözümleyebilir; masaüstü istemciniz ise tamamen farklı bir sağlayıcı adresinden ayrı bir IP adresine çözümleyebilir.

E-posta istemcinizin hangi IMAP sunucusuna bağlandığından bağımsız olarak, bağlantının veritabanınızdan %100 doğrulukla gerçek zamanlı okuma yapmasını istiyoruz. Bu, WebSockets aracılığıyla yapılır.

{#writes}'i yazar

Veritabanınıza yazmak biraz farklıdır; çünkü SQLite gömülü bir veritabanıdır ve posta kutunuz varsayılan olarak tek bir dosyada bulunur.

Aşağıda litestream, rqlite ve dqlite gibi seçenekleri inceledik; ancak bunların hiçbiri gereksinimlerimizi karşılamadı.

Yazma öncesi günlük kaydı ("WAL") etkinleştirilmiş halde yazma işlemlerini gerçekleştirmek için, bunu yapmaktan yalnızca bir sunucunun ("Birincil") sorumlu olduğundan emin olmamız gerekir. WAL eşzamanlılığı önemli ölçüde hızlandırır ve bir yazıcıya ve birden fazla okuyucuya izin verir.

Birincil sunucu, şifreli posta kutularını içeren bağlı birimlere sahip veri sunucularında çalışır. Dağıtım açısından, imap.forwardemail.net'ın arkasındaki tüm bireysel IMAP sunucularını ikincil sunucular ("İkincil") olarak düşünebilirsiniz.

WebSockets ile iki yönlü iletişimi gerçekleştiriyoruz:

  • Birincil sunucular, ws'ın WebSocketServer sunucusunun bir örneğini kullanır.
  • İkincil sunucular, ws'nin WebSocket istemcisinin websocket-söz-verildiği-gibi ve websocket'ı yeniden bağlama ile sarmalanmış bir örneğini kullanır. Bu iki sarmalayıcı, WebSocket'nın yeniden bağlanmasını ve belirli veritabanı yazma işlemleri için veri gönderip alabilmesini sağlar.

Yedeklemeler

tldr; Şifrelenmiş posta kutularınızın yedekleri günlük olarak alınır. Ayrıca, istediğiniz zaman Hesabım Alan Adları Takma Adlar'dan anında yeni bir yedekleme talep edebilir veya en son yedeklemeyi indirebilirsiniz.

Yedeklemeler için, IMAP komut işleme sırasında her gün, bellek içi bir IMAP bağlantısından şifrelenmiş parolanızı kullanan SQLite VACUUM INTO komutunu çalıştırıyoruz. Mevcut bir yedekleme algılanmazsa veya dosyadaki SHA-256 özeti en son yedeklemeye göre değişmişse, yedeklemeler saklanır.

Yerleşik backup komutu yerine VACUUM INTO komutunu kullandığımızı unutmayın; çünkü backup komutu sırasında bir sayfa değiştirilirse, baştan başlamak zorunda kalır. VACUUM INTO komutu anlık görüntü alır. Daha fazla bilgi için GitHub ve Hacker Haberleri hakkındaki yorumlara bakın.

Ayrıca backup yerine VACUUM INTO kullanıyoruz çünkü backup komutu, rekey çağrılana kadar veritabanını kısa bir süreliğine şifrelenmemiş halde bırakacaktır (bilgi için şu GitHub Yorum'e bakın).

İkincil, WebSocket bağlantısı üzerinden Birincil'e yedeklemeyi yürütmesi talimatını verecek ve Birincil daha sonra bunu yapması için komutu alacak ve ardından şunları yapacaktır:

  1. Şifrelenmiş posta kutunuza bağlanın.
  2. Bir yazma kilidi edinin.
  3. wal_checkpoint(PASSIVE) aracılığıyla bir WAL kontrol noktası çalıştırın.
  4. VACUUM INTO SQLite komutunu çalıştırın.
  5. Kopyalanan dosyanın şifrelenmiş parola ile açılabildiğinden emin olun (güvenlik/sahte parola koruması).
  6. Depolama için Cloudflare R2'ye (veya belirtilmişse kendi sağlayıcınıza) yükleyin.

Posta kutularınızın şifrelendiğini unutmayın; WebSocket iletişimi için IP kısıtlamalarımız ve diğer kimlik doğrulama önlemlerimiz olsa da, kötü niyetli bir aktörün saldırısı durumunda, WebSocket yükü IMAP parolanıza sahip olmadığı sürece veritabanınızı açamayacağından emin olabilirsiniz.

Şu anda posta kutusu başına yalnızca bir yedekleme saklanıyor, ancak gelecekte belirli bir zamanda kurtarma ("PITR") sunabiliriz.

{#search}'i arayın

IMAP sunucularımız karmaşık sorgular, düzenli ifadeler ve daha fazlasıyla SEARCH komutunu destekler.

Hızlı arama performansı FTS5 ve sqlite-regex sayesindedir.

Date değerlerini, Date.prototype.toISOString aracılığıyla (eşitlik karşılaştırmalarının düzgün çalışması için UTC zaman dilimiyle) SQLite posta kutularında ISO 8601 dizeleri olarak saklıyoruz.

Ayrıca arama sorgularında yer alan tüm özellikler için endeksler saklanır.

Projeleri

Kaynak kodumuzda ve geliştirme sürecimizde kullandığımız projeleri özetleyen bir tablo aşağıdadır (alfabetik olarak sıralanmıştır):

Proje Amaç
Ansible Tüm sunucu filomuzu kolaylıkla yönetmek, ölçeklendirmek ve sürdürmek için DevOps otomasyon platformu.
Bree Node.js ve JavaScript için cron, dates, ms, later ve kullanıcı dostu desteği olan iş zamanlayıcısı.
Cabin Güvenlik ve gizliliği göz önünde bulunduran, geliştirici dostu JavaScript ve Node.js günlükleme kütüphanesi.
Lad MVC ve daha fazlasıyla tüm mimarimizi ve mühendislik tasarımımızı destekleyen Node.js framework'ü.
MongoDB Posta kutularının dışındaki tüm verileri (örneğin hesabınız, ayarlarınız, alan adlarınız ve takma ad yapılandırmalarınız) depolamak için kullandığımız NoSQL veritabanı çözümü.
Mongoose Tüm yığınımızda kullandığımız MongoDB nesne belge modellemesi ("ODM"). SQLite ile Mongoose kullanmaya devam etmemizi sağlayan özel yardımcılar yazdık: tada:
Node.js Node.js, tüm sunucu süreçlerimizi çalıştıran açık kaynaklı, platformlar arası JavaScript çalışma zamanı ortamıdır.
Nodemailer E-posta göndermek, bağlantı oluşturmak ve daha fazlası için Node.js paketi. Bu projenin resmi sponsoruyuz.
Redis Önbelleğe alma, yayınlama/abone olma kanalları ve HTTPS üzerinden DNS istekleri için bellek içi veritabanı.
SQLite3MultipleCiphers SQLite için tüm veritabanı dosyalarının şifrelenmesine (yazma öncesi günlük ("WAL"), günlük, geri alma, ... dahil) izin veren şifreleme uzantısı.
SQLiteStudio Geliştirme posta kutularını test etmek, indirmek ve görüntülemek için görsel SQLite düzenleyicisi (bunu da kullanabilirsiniz).
SQLite Ölçeklenebilir, kendi kendine yeten, hızlı ve dayanıklı IMAP depolama için gömülü veritabanı katmanı.
Spam Scanner Node.js anti-spam, e-posta filtreleme ve kimlik avı önleme aracı (Spam Assassin ve rspamd'e alternatifimiz).
Tangerine Node.js ile HTTPS üzerinden DNS istekleri ve Redis ile önbellekleme – küresel tutarlılığı ve çok daha fazlasını sağlar.
Thunderbird Geliştirme ekibimiz bunu Forward Email ile kullanılacak tercih edilen e-posta istemcisi olarak kullanıyor (ve öneriyor).
UTM Geliştirme ekibimiz, farklı e-posta istemcilerini (paralel olarak) IMAP ve SMTP sunucularımızla test etmek amacıyla iOS ve macOS için bu sanal makineleri oluşturuyor.
Ubuntu Tüm altyapımızı destekleyen modern, açık kaynaklı Linux tabanlı sunucu işletim sistemi.
WildDuck IMAP sunucu kütüphanesi – attachment de-duplication ve IMAP protocol support hakkındaki notlarına bakın.
better-sqlite3-multiple-ciphers Node.js'in SQLite3 ile programlı olarak etkileşime girmesini sağlayan hızlı ve basit API kütüphanesi.
email-templates Özel e-postalar (örneğin hesap bildirimleri ve daha fazlası) oluşturmak, önizlemek ve göndermek için geliştirici dostu e-posta çerçevesi.
json-sql-enhanced Mongo tarzı sözdizimini kullanan SQL sorgu oluşturucu. Bu, veritabanından bağımsız bir yaklaşımla tüm yığında Mongo tarzında yazmaya devam edebileceğimiz için geliştirme ekibimize zaman kazandırıyor. Ayrıca, sorgu parametreleri kullanılarak SQL enjeksiyon saldırılarından kaçınmaya da yardımcı oluyor.
knex-schema-inspector Mevcut veritabanı şeması hakkında bilgi çıkarmak için SQL yardımcı programı. Bu, tüm dizinlerin, tabloların, sütunların, kısıtlamaların ve daha fazlasının geçerli olduğunu ve olması gerektiği gibi 1:1 olduğunu kolayca doğrulamamızı sağlar. Hatta veritabanı şemalarında değişiklik yapıldığında yeni sütunlar ve dizinler eklemek için otomatik yardımcılar bile yazdık (son derece ayrıntılı hata uyarılarıyla birlikte).
knex Sadece veritabanı geçişleri ve knex-schema-inspector aracılığıyla şema doğrulaması için kullandığımız SQL sorgu oluşturucusu.
mandarin Google Cloud Translation API kullanılarak Markdown desteğiyle otomatik i18n cümle çevirisi.
mx-connect MX sunucuları ile bağlantı kurmak ve hataları çözmek için Node.js paketi.
pm2 Dahili yük dengeleyiciye sahip Node.js üretim süreci yöneticisi (performans için fine-tuned).
smtp-server SMTP sunucu kütüphanesi – bunu posta değişim ("MX") ve giden SMTP sunucularımız için kullanıyoruz.
ImapTest IMAP sunucularını kıyaslama ölçütlerine ve RFC spesifikasyonu IMAP protokolü uyumluluğuna göre test etmek için kullanışlı bir araç. Bu proje, Dovecot ekibi (Temmuz 2002'den beri aktif bir açık kaynaklı IMAP ve POP3 sunucusu) tarafından oluşturulmuştur. IMAP sunucumuzu bu araçla kapsamlı bir şekilde test ettik.

GitHub'daki kaynak kodumuz'da kullandığımız diğer projeleri bulabilirsiniz.

Sağlayıcıları

Sağlayıcı Amaç
Cloudflare DNS sağlayıcısı, sağlık kontrolleri, yük dengeleyiciler ve Cloudflare R2 kullanılarak yedekleme depolaması.
Digital Ocean Özel sunucu barındırma ve yönetilen veritabanları.
Vultr Adanmış sunucu barındırma.
DataPacket Adanmış sunucu barındırma.

Düşünceler

İlkeleri

Forward Email şu prensiplere göre tasarlanmıştır:

  1. Her zaman geliştirici dostu, güvenlik ve gizlilik odaklı ve şeffaf olun.
  2. MVC, Unix, KISS, DRY, YAGNI, On İki Faktör, Occam'ın usturası ve köpek maması'ye uyun.
  3. Dağınık, önyüklemeli ve ramen-kârlı geliştiricilerini hedefleyin.

Deneyler

kısacası; Sonuç olarak S3 uyumlu nesne depolama ve/veya Sanal Tabloların kullanımı performans nedenlerinden dolayı teknik olarak mümkün değildir ve bellek kısıtlamaları nedeniyle hataya açıktır.

Yukarıda tartıştığımız gibi nihai SQLite çözümümüze ulaşana kadar birkaç deney yaptık.

Bunlardan biri, rclone ve SQLite'ı S3 uyumlu bir depolama katmanıyla birlikte kullanmayı denemekti.

Bu deney, rclone, SQLite ve VFS kullanımını çevreleyen uç durumları daha iyi anlamamızı ve keşfetmemizi sağladı:

  • --vfs-cache-mode writes işaretini rclone ile etkinleştirirseniz, okumalar sorunsuz olur, ancak yazmalar önbelleğe alınır.
  • Dünya çapında dağıtılmış birden fazla IMAP sunucunuz varsa, tek bir yazıcı ve birden fazla dinleyiciniz (örneğin, bir yayınla/abone ol yaklaşımı) olmadığı sürece önbellek bunlar arasında kapalı olacaktır.
  • Bu inanılmaz derecede karmaşıktır ve bu tür ek karmaşıklıkların eklenmesi, daha fazla tekil hata noktasına yol açacaktır.
  • S3 uyumlu depolama sağlayıcıları kısmi dosya değişikliklerini desteklemez; bu da .sqlite dosyasında yapılan herhangi bir değişikliğin, veritabanının tamamen değiştirilmesine ve yeniden yüklenmesine neden olacağı anlamına gelir.
  • rsync gibi başka çözümler de mevcuttur, ancak bunlar önceden yazma günlüğü ("WAL") desteğine odaklanmadığından, Litestream'i incelemeye karar verdik. Neyse ki şifreleme kullanımımız zaten WAL dosyalarını bizim için şifreliyor, bu nedenle bunun için Litestream'e güvenmemize gerek yok. Ancak Litestream'in üretim kullanımı için henüz yeterli güvene sahip olmadığımızı düşünüyoruz ve bu konuda aşağıda birkaç notumuz var.
  • --vfs-cache-mode writes seçeneğinin (yazma işlemleri için rclone yerine SQLite kullanmanın tek yolu) kullanılması, tüm veritabanını sıfırdan belleğe kopyalamaya çalışacaktır. 10 GB'lık tek bir posta kutusunu yönetmek sorun değil, ancak aşırı yüksek depolama alanına sahip birden fazla posta kutusunu yönetmek, IMAP sunucularının bellek sınırlamaları ve ENOMEM hataları, segmentasyon hataları ve veri bozulmasıyla karşılaşmasına neden olacaktır. * Verileri S3 uyumlu bir depolama katmanında canlı tutmak için SQLite Sanal Tablolar (örneğin s3db kullanarak) kullanmaya çalışırsanız, birkaç sorunla daha karşılaşırsınız:
  • S3 API uç noktalarının HTTP .sqlite0, .sqlite1, .sqlite2 ve .sqlite3 yöntemleriyle etkilenmesi gerekeceğinden, okuma ve yazma işlemleri son derece yavaş olacaktır.
  • Geliştirme testleri, fiber internette 500.000-1 milyon+ kaydın, S3 uyumlu sağlayıcılara yazma ve okuma kapasitesiyle sınırlı olduğunu göstermiştir. Örneğin, geliştiricilerimiz hem sıralı SQL .sqlite5 ifadelerini hem de büyük miktarda veriyi toplu olarak yazan ifadeleri gerçekleştirmek için .sqlite4 döngülerini çalıştırdı. Her iki durumda da performans şaşırtıcı derecede yavaştı.
  • Sanal tablolar indekslere, .sqlite6 ifadelerine ve .sqlite7 .sqlite8'e sahip olamaz; bu da veri miktarına bağlı olarak 1-2 dakika veya daha fazla gecikmeye yol açar.
  • Nesneler şifrelenmemiş olarak depolandı ve yerel şifreleme desteği mevcut değil.
  • Ayrıca, kavramsal ve teknik olarak önceki madde işaretine benzer olan .sqlite9'u kullanmayı da araştırdık (bu nedenle aynı sorunları yaşıyor). Bir olasılık, rsync1 (şu anda yukarıdaki çözümümüzde kullandığımız) gibi rsync2 aracılığıyla şifrelemeyle sarılmış özel bir rsync0 derlemesi kullanmak olabilir.
  • Bir diğer olası yaklaşım ise rsync3'ü kullanmaktı, ancak bunun 32 GB'lık bir sınırlaması var ve karmaşık derleme ve geliştirme sorunları gerektirecektir. * rsync4 ifadeleri gereklidir (bu nedenle Sanal Tabloların kullanımı tamamen devre dışıdır). rsync6 ile olan kancamızın düzgün çalışması için rsync5 ifadelerine ihtiyacımız var; bu, verilerin bozulmamasını ve alınan satırların rsync7 şema tanımlarımıza (kısıtlama, değişken türü ve keyfi veri doğrulaması dahil) göre geçerli belgelere dönüştürülebilmesini sağlar.
  • Açık kaynak topluluğundaki SQLite ile ilgili S3 uyumlu projelerin neredeyse tamamı Python'dadır (yığınımızın %100'ü için kullandığımız JavaScript değil).
  • rsync8 (bkz. rsync9) gibi sıkıştırma kütüphaneleri umut verici görünüyor, ancak __PROTECTED_LINK_189__0. __PROTECTED_LINK_189__1, __PROTECTED_LINK_189__2, __PROTECTED_LINK_189__3, __PROTECTED_LINK_189__4, __PROTECTED_LINK_189__5 ve __PROTECTED_LINK_189__6 gibi veri türlerinde uygulama tarafı sıkıştırma daha temiz ve daha kolay bir yaklaşım olacaktır (ve ayrıca geçişi de daha kolaydır, çünkü bir __PROTECTED_LINK_189__7 bayrağı veya sütunu depolayabiliriz - hatta sıkıştırma için __PROTECTED_LINK_189__8 __PROTECTED_LINK_189__9 veya sıkıştırma olmaması için __PROTECTED_LINK_190__0'ı veritabanı meta verileri olarak kullanabiliriz).
  • Neyse ki, IMAP sunucu depolamamızda ek çoğaltma önleme özelliği zaten uygulanmıştır - bu nedenle aynı eki olan her ileti, ekin bir kopyasını tutmaz - bunun yerine, bir posta kutusunda birden fazla ileti ve iş parçacığı için tek bir ek depolanır (ve daha sonra yabancı bir referans kullanılır). * SQLite replikasyon ve yedekleme çözümü olan Litestream projesi oldukça umut verici ve büyük olasılıkla gelecekte de kullanacağız.
  • Yazar(lar)ı itibarsızlaştırmak istemem - çünkü çalışmalarını ve açık kaynaklı yazılımlara katkılarını on yıldan uzun süredir seviyoruz - ancak gerçek dünyadaki kullanımdan, __PROTECTED_LINK_190__1 ve __PROTECTED_LINK_190__2 olduğu anlaşılıyor.
  • Yedekleme geri yüklemesinin sorunsuz ve basit olması gerekiyor. __PROTECTED_LINK_190__3 ve __PROTECTED_LINK_190__4 içeren MongoDB gibi bir çözüm kullanmak sadece sıkıcı değil, aynı zamanda zaman alıcı ve yapılandırma karmaşıklığı da içeriyor.
  • SQLite veritabanları bunu basitleştiriyor (tek bir dosya).
  • Kullanıcıların posta kutularını istedikleri zaman alıp bırakabilecekleri bir çözüm tasarlamak istedik.
  • __PROTECTED_LINK_190__5'e basit Node.js komutları ve disk depolama alanından kalıcı olarak silinmesi. * Benzer şekilde, kullanıcılar için anlık görüntüleri ve yedekleri kolayca kaldırmak amacıyla HTTP __PROTECTED_LINK_190__6 ile S3 uyumlu bir API kullanabiliriz.
  • SQLite en basit, en hızlı ve en uygun maliyetli çözümdü.

Alternatif eksikliği

Bildiğimiz kadarıyla, başka hiçbir e-posta hizmeti bu şekilde tasarlanmamıştır ve açık kaynaklı değildir.

Bunun, mevcut e-posta servislerinin spagetti kodu 🍝 ile üretimde eski teknolojiye sahip olmasından kaynaklandığını düşünüyoruz.

Mevcut e-posta servis sağlayıcılarının çoğu, hatta hepsi, ya kapalı kaynaklıdır ya da açık kaynaklı olduklarını iddia ederler, ama gerçekte yalnızca ön yüzleri açık kaynaklıdır.

E-postanın en hassas kısmı (gerçek depolama/IMAP/SMTP etkileşimi) tamamen arka uçta (sunucu) yapılır ve ön uçta (istemci) değildir.

E-postayı İlet'i deneyin

Bugün https://forwardemail.net! 🚀 adresinden kaydolun