-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration vi
Từ 1.9.0, cấu hình SkimMail chia thành ba "mặt phẳng" (plane) — ba chỗ khác nhau mà một setting có thể sống, mỗi chỗ có vòng đời riêng và cách đổi riêng. Biết một setting nằm ở plane nào cho bạn biết chính xác phải đổi nó ở đâu và khi nào thay đổi đó có hiệu lực. Quy tắc quan trọng nhất, chỉ một câu: cái gì bạn đặt trong environment luôn thắng.
Đúng năm key: DATA_DIR, DB_DRIVER, DATABASE_URL, KEY_PROVIDER,
LISTEN_ADDR. Chúng tồn tại để trả lời đúng một câu hỏi — database nằm ở
đâu, và mở nó bằng cách nào? — câu hỏi phải được trả lời trước khi có
database để lưu bất cứ thứ gì khác.
-
DATA_DIRchỉ đặt được qua environment, vĩnh viễn. Nó không thể nằm ở đâu khác, vì nó chính là tên thư mục chứa mọi thứ khác (kể cả file nói ở dưới) sống trong đó. - Bốn key còn lại có thể đặt qua environment variable, hoặc ghi vào
<DATA_DIR>/bootstrap.env— một file nhỏ do chính SkimMail quản lý, qua bước chọn database của setup wizard lần đầu hoặc quaskimmail config set. File này tồn tại chính là để người cài bằng một dòngcurl | shrồi muốn dùng Postgres có chỗ để đặt DSN mà không phải tự tay sửa một systemdEnvironmentFile. - Thứ tự ưu tiên: environment thắng file, file thắng giá trị mặc định sẵn có.
- Thay đổi ở đây có hiệu lực sau lần restart tiếp theo — không có gì ở đây được nạp lại khi đang chạy (live-reload), vì nó quyết định mở tiến trình database nào ngay từ đầu.
Ví dụ cụ thể. Một bản apt mới cài, không đặt DATABASE_URL trong
/etc/default/skimmail, sẽ chạy SQLite tại
/var/lib/skimmail/skimmail.db (mặc định sẵn có). Trỏ setup wizard lần đầu
vào một Postgres sẽ ghi DB_DRIVER=postgres và DATABASE_URL=postgres://…
vào /var/lib/skimmail/bootstrap.env rồi restart tiến trình để dùng nó. Nếu
sau đó bạn thêm DATABASE_URL=… thẳng vào /etc/default/skimmail, environment
giờ thắng — giá trị trong bootstrap.env bị bỏ qua từ lúc đó, dù nó vẫn còn
nằm trong file.
Những setting quyết định SkimMail này hiện diện trên mạng ra sao: public
URL, base path, có tin một reverse proxy hay không, các origin CORS/CSRF phụ
thêm, chế độ đăng nhập, và OAuth app credentials của Google/Microsoft. Trước
1.9.0, mỗi cái này là một environment variable chỉ đổi được bằng cách sửa
file rồi restart; giờ chúng lưu trong database và chỉnh được từ
Settings trên trình duyệt, hoặc từ shell bằng skimmail config.
| Setting | Key trong skimmail config
|
Environment variable |
|---|---|---|
| Public URL | base_url |
BASE_URL |
| Base path (phục vụ dưới subpath) | base_path |
BASE_PATH |
| Tin một reverse proxy | trust_proxy |
TRUST_PROXY |
| Origin CORS/CSRF phụ thêm | trusted_origins |
TRUSTED_ORIGINS |
| Chế độ đăng nhập | auth.mode |
AUTH_MODE |
| Google OAuth client ID / secret |
oauth.google.client_id / oauth.google.client_secret
|
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET
|
| Microsoft OAuth client ID / secret |
oauth.microsoft.client_id / oauth.microsoft.client_secret
|
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET
|
- Thứ tự ưu tiên: environment luôn thắng, và thắng tuyệt đối. Một field
mà environment cung cấp sẽ hiện locked trên trình duyệt, nêu đúng tên
biến cần xoá nếu bạn muốn quản lý nó từ app thay vì từ environment. Một
lần ghi vào field đang locked — dù từ trình duyệt hay từ
skimmail config set— đều bị từ chối, không phải bị âm thầm ghi đè. - Thay đổi có hiệu lực ngay lập tức — không cần restart. Server giữ cấu hình đã resolve sau một con trỏ mà nó hoán đổi mỗi lần lưu, đó là lý do vì sao sửa OAuth app hay public URL từ Settings có tác dụng ngay mà không cần restart.
- OAuth client secret được mã hoá at-rest bằng master key (xem
Security) và không bao giờ được trả về qua bất kỳ lần đọc
nào — API và
skimmail config listchỉ báo được là secret có được đặt hay không. - Chế độ đăng nhập có thêm một quy tắc riêng: một khi đã có credential, trình
duyệt không thể đổi nó nữa — chỉ
skimmail config set auth.mode …trên host mới đổi được, và đặt vềnonecòn đòi thêmSKIMMAIL_ALLOW_AUTH_NONE=1trong environment. Một admin session bị đánh cắp không thể tự tắt xác thực.
Ví dụ cụ thể. Bạn đặt BASE_URL=https://mail.example.com trong
/etc/default/skimmail vì bạn quản lý instance này theo kiểu khai báo
(declarative). Settings ▸ (setup/about) giờ hiện Public URL ở trạng thái
locked, nêu tên BASE_URL là biến cần xoá nếu bạn muốn quản lý nó từ trình
duyệt thay vào đó. Cho tới khi bạn xoá nó ở đó và restart, mọi lần thử sửa —
từ trình duyệt hay skimmail config set base_url … — đều bị từ chối với
cùng một thông báo.
Các nút chỉnh runtime cho từng tính năng cụ thể: thời gian chờ trước khi screen lock và thời lượng session (Security), concurrency/rate/depth của sync và hành vi IDLE/poll (Sync), log level và xoay vòng file log (Logs). Những cái này có từ trước công việc cấu hình 1.9.0 và theo quy tắc đơn giản hơn, một chiều:
- Environment variable chỉ cung cấp giá trị mặc định ở lần đầu tiên — trước khi setting đó từng được lưu lần nào.
- Ngay khi bạn lưu một thay đổi từ tab Settings tương ứng, giá trị đã lưu thắng từ đó về sau — kể cả qua mọi lần restart sau này — bất kể environment variable còn được đặt hay không. Không có chỉ báo "locked" ở đây, vì không có gì để lock: một khi đã lưu, environment variable đơn giản không còn được tham khảo lại cho key đó nữa.
- Những setting này không nằm trong phạm vi
skimmail config— lệnh đó chỉ là lối thoát hiểm cho Plane 0 và Plane 1.
Ví dụ cụ thể. AUTO_LOCK_MINUTES chưa đặt, nên screen lock mặc định tắt
(mặc định sẵn có là 0, không bao giờ khoá). Bạn bật nó lên và đặt 15 phút
trong Settings ▸ Security ▸ Timeouts. Con số 15 đó giờ nằm trong database
và áp dụng ở mọi lần restart. Đặt AUTO_LOCK_MINUTES=30 trong environment
sau đó không đổi được gì — giá trị bạn đã lưu đã thắng rồi, và tiếp tục
thắng cho tới khi bạn đổi lại từ chính tab Settings đó.
Có vài key trông như thuộc về một tính năng ở trên nhưng thật ra chỉ đọc lúc
khởi động, hết — không có khoá kiểu Plane-1, không có ghi đè kiểu Plane-2,
không bao giờ: TRUSTED_PROXIES (xem Security), và
LOG_FILE/LOG_FORMAT (đường dẫn log cố tình không bao giờ đặt được qua
API — làm vậy sẽ thành ghi file tuỳ ý từ trình duyệt).
Cột "Plane" nói thay đổi đã lưu (nếu có) nằm ở đâu; cột mô tả nói environment variable làm gì với plane đó.
| Biến | Làm gì | Mặc định |
|---|---|---|
DATA_DIR |
Nơi database, blob và master key sống | ./data |
DB_DRIVER |
sqlite | postgres | mysql
|
sqlite |
DATABASE_URL |
Connection string khi DB_DRIVER khác sqlite
|
(rỗng) |
KEY_PROVIDER |
file (master key thô trên đĩa) | passphrase (đã bọc) |
file |
LISTEN_ADDR |
Địa chỉ HTTP server lắng nghe | :8080 |
| Biến | Làm gì | Mặc định |
|---|---|---|
BASE_URL |
Public URL — OAuth redirect, WebSocket origin, PWA manifest | (rỗng) |
BASE_PATH |
Phục vụ app dưới một subpath, ví dụ /mail
|
/ |
AUTH_MODE |
passphrase | users | none
|
passphrase |
TRUST_PROXY |
Tin X-Forwarded-* từ các hop proxy được công nhận |
false |
TRUSTED_ORIGINS |
Origin CORS/CSRF phụ thêm, cách nhau bằng dấu phẩy | (rỗng) |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET
|
OAuth app Google của riêng bạn, cho đăng nhập Gmail | (rỗng) |
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET
|
Azure app của riêng bạn, cho đăng nhập Outlook | (rỗng) |
Đăng ký hai redirect URI trên mỗi ứng dụng OAuth, không phải một:
<BASE_URL>/api/oauth/callbackcho cách thường, vàhttp://localhost:8642cho cách dán tay mà các instance không có địa chỉ HTTPS công khai dựa vào. Cả hai đều hiện kèm nút Copy dưới Settings ▸ About ▸ Setup health ▸ OAuth. Cái thứ hai không phải một setting và không có biến môi trường nào — không có gì lắng nghe ở đó, nó chỉ là một chuỗi mà nhà cung cấp cần nhận ra. Xem mục "Thêm một tài khoản Gmail hoặc Outlook (OAuth)" ở Accounts. Các bước cụ thể trên console để đăng ký ứng dụng ở Google và Microsoft, xem Register the OAuth application.
| Biến | Làm gì | Mặc định |
|---|---|---|
SKIMMAIL_ALLOW_AUTH_NONE |
Bắt buộc phải có, cùng với auth.mode=none, trước khi xác thực thật sự bị tắt được |
false (1/true để bật) |
SKIMMAIL_SKIP_CLAIM |
Bỏ qua cổng claim code lần đầu (xem Security) | false |
TRUSTED_PROXIES |
Danh sách CIDR (cách nhau bằng dấu phẩy) được tin là hop của X-Forwarded-For
|
(rỗng = chỉ loopback/private) |
| Biến | Làm gì | Mặc định |
|---|---|---|
AUTO_LOCK_MINUTES |
Số phút không hoạt động trước khi client tự khoá màn hình; 0 = không bao giờ |
0 |
SESSION_TTL_HOURS |
Thời lượng session đăng nhập; 0 = không bao giờ hết hạn |
720 (30 ngày) |
BACKGROUND_POLL_INTERVAL |
Chu kỳ poll dự phòng cho mỗi tài khoản | 5m |
MAX_CONCURRENT_SYNCS |
Số mailbox sync cùng lúc | 4 |
SYNC_RATE_PER_MIN |
Số lần bắt đầu sync tối đa mỗi phút | 10 |
SYNC_DEPTH_DAYS |
Cửa sổ sync header tính theo ngày; 0 = toàn bộ lịch sử |
30 |
SYNC_MAX_RETRIES |
Số lần lỗi liên tiếp trước khi tự dừng sync một tài khoản; 0 = không bao giờ |
3 |
CACHE_MAX_SIZE_MB |
Dọn bớt nội dung thư đã cache khi vượt tổng này; 0 = không giới hạn |
2048 |
BODY_TTL_DAYS |
Xoá nội dung thư đã cache cũ hơn số ngày này; 0 = không bao giờ hết hạn |
90 |
CLIENT_IDLE_GRACE |
Khoảng thời gian không có client trước khi idle-downscale | 30m |
IDLE_DOWNSCALE_WHEN_NO_CLIENT |
Hạ IDLE→poll khi không có trình duyệt nào mở | false |
MAX_IDLE_CONNECTIONS |
Giới hạn số kết nối IMAP IDLE cùng lúc; 0 = không giới hạn |
0 |
LOG_LEVEL |
debug | info | warn | error
|
info |
LOG_MAX_SIZE_MB |
Xoay vòng file log ở kích thước này | 10 |
LOG_MAX_BACKUPS |
Số file log đã xoay vòng được giữ lại | 3 |
CACHE_MAX_SIZE_MB và BODY_TTL_DAYS đúng nghĩa là Plane 2: environment cấp
giá trị khởi tạo, còn giá trị bạn lưu từ Settings ▸ Security ▸ Cache nội
dung thư — hoặc qua PUT /api/settings/cache — được ghi vào database và
thắng từ đó trở đi. Lưu ý đây là chiều ngược với Plane 1, nơi đặt biến là khoá
luôn ô nhập: ở đây environment nhường cho giá trị đã lưu, nên panel đó không
hiện gợi ý "environment đang giữ quyền" nào cả.
Panel này có từ 1.11.1. Ở 1.11.0 nó đã được dựng nhưng đặt trong tab Storage đang ẩn, nên không bản cài nào mở được, và khi đó environment thật sự là con đường duy nhất. Xem Cache nội dung thư.
| Biến | Làm gì | Mặc định |
|---|---|---|
MAX_CONNS_PER_ACCOUNT |
Số kết nối IMAP cùng lúc cho mỗi tài khoản (giới hạn 1–14) | 10 |
BLOB_ENCRYPT |
Mã hoá nội dung thư đã cache trên đĩa (AES-256-GCM, khoá dẫn xuất từ master key). Đọc thì luôn giải mã, nên tắt đi không bao giờ làm mất cache đang có. Luôn bật trừ khi bạn tắt tường minh: chỉ false, 0, no và off mới tắt (không phân biệt hoa thường, bỏ qua khoảng trắng hai đầu). Mọi giá trị khác — 1, TRUE, yes, on, hay một lỗi gõ — đều để mã hoá bật
|
true |
LOG_FILE |
Đường dẫn file log xoay vòng; rỗng = chỉ stdout/journal | (rỗng; apt tự đặt /var/log/skimmail/skimmail.log) |
LOG_FORMAT |
text (key=value) | json
|
text |
FIREBASE_ENABLED / FIREBASE_CREDENTIALS
|
Push trên di động qua Firebase (FCM), tuỳ chọn; hầu hết người tự host không cần cái này — Web Push trên trình duyệt hoạt động mà không cần cấu hình gì |
false / (rỗng)
|
VAPID_PUBLIC / VAPID_PRIVATE / VAPID_SUBJECT
|
Ghi đè cặp khoá Web Push được tự sinh | (rỗng — một cặp khoá được tự sinh và lưu lại) |
UPDATE_FEED_URL |
Ghi đè release feed cho self-update (dùng cho mirror air-gapped) | (rỗng = GitHub Releases) |
UPDATE_PUBKEY |
Khoá công khai minisign dùng xác minh self-update và chữ ký manifest plugin. Bản build chính thức đã gắn sẵn; chỉ đặt biến này trên bản build tuỳ chỉnh | (rỗng trên bản build tuỳ chỉnh = update chỉ dừng ở thông báo, manifest plugin không được xác minh) |
REVOCATION_FEED_URL |
Ghi đè nơi lấy danh sách license-id đã bị thu hồi | (rỗng = feed mặc định) |
SKIMMAIL_PLUGINS_URL |
Ghi đè nơi tải plugins.json (danh mục plugin Remote access / WireGuard engine) |
(rỗng = manifest GitHub Pages mặc định) |
BLOB_ENCRYPT là boolean duy nhất trong bảng này mặc định bật, và cũng là
cái duy nhất coi một giá trị không nhận diện được là "bật". Mọi công tắc khác ở
đây mặc định tắt, nơi việc không hiểu một giá trị là chiều vô hại; một cờ mặc
định bật thì ngược lại, nên nó phải hỏng về phía vẫn mã hoá.
Nếu bạn đang chạy 1.11.0, hãy kiểm tra biến này. Bản đó so giá trị với đúng chữ
true, nênBLOB_ENCRYPT=1,=yes,=onvà=TRUEđều đọc ra tắt và lặng lẽ ngừng mã hoá nội dung thư mới. Đã sửa ở 1.11.1. Những nội dung đã cache trong lúc bị tắt không được ghi đè tại chỗ; chúng nằm nguyên không mã hoá cho tới khi rời khỏi cache. Hạ giới hạn dung lượng hoặc tuổi trong Settings ▸ Security sẽ đẩy chúng ra, và chúng quay lại ở dạng đã mã hoá.
Công cụ AI là mảng tính năng duy nhất đã compile sẵn vào binary mà tab Settings của nó vẫn bị ẩn ở 1.15.0 — environment variable của nó cố tình bị bỏ khỏi bảng này cho tới khi tab đó được bật lại. Công tắc storage engine / S3 blob trước đây bị ẩn cùng với nó và đã hiện từ 1.14.0, nên các thiết lập của nó giờ nằm ở Settings ▸ Storage. Các biến body cache ở trên từng chung số phận ấy sớm hơn; từ 1.11.1 panel của chúng nằm ở Settings ▸ Security. Xem Home để biết cái gì đang bị ẩn và vì sao.
Mọi thứ Plane 1 cho làm trên trình duyệt, skimmail config cũng làm được
trên host — cộng thêm một việc trình duyệt không làm được một khi đã có
credential: đổi chế độ đăng nhập.
skimmail config list # mọi setting, giá trị, và nó đến từ đâu
skimmail config get base_url # một giá trị, in trần, để dùng trong script
skimmail config set base_url https://mail.example.com
skimmail config unset base_url # xoá nó
skimmail config export # khối env tương ứng với những gì đang trong databaselist in setting của Plane 1 và các key bootstrap của Plane 0 thành hai
bảng riêng (đổi bootstrap cần restart mới có hiệu lực; đổi Plane 1 thì
không, và lệnh có nói rõ điều đó). export bỏ qua secret — chúng đã mã hoá
at-rest và không đọc ngược lại được; lệnh in ra một dòng comment nhắc bạn
dán lại secret bằng tay. Thử set một key mà environment đã sở hữu sẽ lỗi
với cùng thông báo "xoá nó ở environment trước" mà trình duyệt hiển thị.
Đây cũng là đường quay lại nếu bạn từng tự khoá mình khỏi chế độ đăng nhập
trên trình duyệt, và là nơi duy nhất auth.mode đổi được một khi đã có tài
khoản.
bootstrap.env cố tình rất hẹp — DB_DRIVER, DATABASE_URL, KEY_PROVIDER
và LISTEN_ADDR, không hơn (DATA_DIR không bao giờ có thể nằm trong đó:
chính nó là nơi file này sống) — và Plane 1 không bao giờ có thêm một file
riêng song song với database. Cho cùng một setting hai
"nhà" đều ghi được độc lập (một file và một dòng database, cả hai đều
tự nhận là nguồn chân lý) chính là cách một dự án tự host khác từng có một
admin UI âm thầm không lưu được thay đổi, vì một config file mà UI không hề
biết tới cứ lặng lẽ thắng mỗi lần. Quy tắc của SkimMail giữ đơn giản vì nó
chỉ cần đúng theo một chiều: environment thắng tất cả, và mọi thứ khác
chỉ sống ở đúng một chỗ duy nhất.
SkimMail · skimmail@base101.app · 2026-09-18 · commit f525934