رابط برنامهنویسی مدیریتی (Admin API) به شما امکان مدیریت کامل سرور از طریق HTTP را میدهد. تمام عملیاتهایی که از طریق خط فرمان (CLI) قابل انجام هستند، از طریق این API نیز در دسترساند.
/admin/status/admin/storage/admin/registration/admin/registration/jit/admin/services/turn/admin/services/iroh/admin/services/shadowsocks/admin/services/log/admin/settings/admin/accounts/admin/blocklist/admin/quota/admin/queue/admin/shares/admin/dnsAdmin API از یک معماری RPC تکنقطه (Single-Endpoint RPC) استفاده میکند. به جای داشتن مسیرهای HTTP مختلف برای هر عملیات، تمام درخواستها به یک آدرس واحد ارسال میشوند:
توکن مدیریتی به صورت خودکار در اولین اجرای سرور تولید و در مسیر
/var/lib/maddy/admin_token ذخیره میشود. این توکن شامل ۲۵۶ بیت آنتروپی رمزنگاریشده است
و در هر بار راهاندازی مجدد حفظ میشود.
# Show current token maddy admin-token # Save to variable TOKEN=$(maddy admin-token)
شما میتوانید در فایل maddy.conf یکی از تنظیمات زیر را اعمال کنید:
# Set custom token admin_token your-custom-secret-token # Disable API entirely admin_token disabled
0600 (فقط قابل خواندن توسط root) ذخیره میشود.
توکن هیچگاه در لاگها ثبت نمیشود و مقایسه آن به صورت ثابتزمان (constant-time) انجام میشود.
تمام درخواستها باید به صورت POST به آدرس /api/admin ارسال شوند:
{
"method": "GET",
"resource": "/admin/status",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
},
"body": {}
}
method — متد عملیات: GET، POST، PUT،
DELETE
resource — مسیر منبع مورد نظرheaders — هدرهای داخلی (شامل توکن احراز هویت)body — بدنه اختیاری (بسته به عملیات)تمام پاسخها با فرمت یکسان بازگردانده میشوند:
{
"status": 200,
"resource": "/admin/status",
"body": { ... },
"error": null
}
status — کد وضعیت واقعی عملیاتresource — مسیر منبع درخواستشدهbody — دادههای بازگشتی (در صورت موفقیت)error — پیام خطا (در صورت شکست، در غیر اینصورت null)200 است. برای بررسی نتیجه واقعی، فیلد status در بدنه JSON
را بررسی کنید.
نمونهای ساده از استفاده با curl:
# Get token TOKEN=$(maddy admin-token) # Check server status curl -s -X POST https://your-server/api/admin \ -H 'Content-Type: application/json' \ -d "{ \"method\": \"GET\", \"resource\": \"/admin/status\", \"headers\": {\"Authorization\": \"Bearer $TOKEN\"} }" | python3 -m json.tool
یا با استفاده از اسکریپت پایتون:
import requests
TOKEN = "your-admin-token"
BASE = "https://your-server"
def api(resource, method="GET", body=None):
resp = requests.post(f"{BASE}/api/admin", json={
"method": method,
"resource": resource,
"headers": {"Authorization": f"Bearer {TOKEN}"},
"body": body or {},
})
return resp.json()
# Example: get status
print(api("/admin/status"))
نمایش وضعیت کلی سرور شامل تعداد کاربران، آپتایم و آمار سرورهای ایمیل.
درخواست:{
"method": "GET",
"resource": "/admin/status",
"headers": {"Authorization": "Bearer TOKEN"}
}
پاسخ:
{
"status": 200,
"body": {
"users": {
"registered": 799
},
"uptime": {
"boot_time": "2026-02-17T20:51:21Z",
"duration": "2d 5h 30m 15s"
},
"email_servers": {
"connection_ips": 12,
"domain_servers": 8,
"ip_servers": 3
}
}
}
| Field | Type | Description |
|---|---|---|
users.registered |
int | Total registered accounts |
uptime.boot_time |
string | Server boot time (RFC3339) |
uptime.duration |
string | Human-readable uptime |
email_servers.connection_ips |
int | Unique connecting IPs since boot |
email_servers.domain_servers |
int | Unique domain servers seen |
email_servers.ip_servers |
int | Unique IP-based servers seen |
اطلاعات دیسک، پوشه داده و حجم دیتابیس.
پاسخ:{
"status": 200,
"body": {
"disk": {
"total_bytes": 53687091200,
"used_bytes": 18253611008,
"available_bytes": 35433480192,
"percent_used": 34.0
},
"state_dir": {
"path": "/var/lib/maddy",
"size_bytes": 1073741824
},
"database": {
"driver": "sqlite3",
"size_bytes": 52428800
}
}
}
باز و بسته کردن ثبتنام کاربران جدید.
مشاهده وضعیت فعلی:// Request {"method": "GET", "resource": "/admin/registration", ...} // Response {"status": 200, "body": {"status": "open"}}تغییر وضعیت:
// Close registration {"method": "POST", "resource": "/admin/registration", "body": {"action": "close"}, ...} // Open registration {"method": "POST", "resource": "/admin/registration", "body": {"action": "open"}, ...}
| Action | Description |
|---|---|
open |
Allow new user registration |
close |
Block new registrations, existing users unaffected |
فعال/غیرفعال کردن ثبتنام آنی. وقتی فعال باشد، حساب کاربری در اولین لاگین بهصورت خودکار ساخته میشود.
// Enable {"method": "POST", "resource": "/admin/registration/jit", "body": {"action": "enable"}, ...} // Disable {"method": "POST", "resource": "/admin/registration/jit", "body": {"action": "disable"}, ...} // Response {"status": 200, "body": {"status": "enabled"}}
فعال/غیرفعال کردن سرور TURN برای تماسهای صوتی و تصویری.
// Enable {"method": "POST", "resource": "/admin/services/turn", "body": {"action": "enable"}, ...} // Disable {"method": "POST", "resource": "/admin/services/turn", "body": {"action": "disable"}, ...}
فعال/غیرفعال کردن سرور رله Iroh برای اتصالات Webxdc بلادرنگ.
// Enable {"method": "POST", "resource": "/admin/services/iroh", "body": {"action": "enable"}, ...} // Disable {"method": "POST", "resource": "/admin/services/iroh", "body": {"action": "disable"}, ...}
فعال/غیرفعال کردن پروکسی Shadowsocks. این سرویس برای عبور از سانسور استفاده میشود.
// Enable {"method": "POST", "resource": "/admin/services/shadowsocks", "body": {"action": "enable"}, ...} // Disable {"method": "POST", "resource": "/admin/services/shadowsocks", "body": {"action": "disable"}, ...}
فعال/غیرفعال کردن ثبت لاگ سرور (سیاست بدون لاگ).
// Enable {"method": "POST", "resource": "/admin/services/log", "body": {"action": "enable"}, ...} // Disable {"method": "POST", "resource": "/admin/services/log", "body": {"action": "disable"}, ...}
دریافت تمام تنظیمات سرور در یک درخواست واحد. شامل کلیدهای روشن/خاموش، پورتها و تنظیمات پیکربندی.
// Request {"method": "GET", "resource": "/admin/settings", ...} // Response (partial) { "status": 200, "body": { "registration": "closed", "turn_enabled": "enabled", "iroh_enabled": "enabled", "ss_enabled": "enabled", "smtp_port": {"key": "__SMTP_PORT__", "value": "2525", "is_set": true}, "turn_secret": {"key": "__TURN_SECRET__", "value": "", "is_set": false} } }
هر پورت سرویسی از طریق یک مسیر اختصاصی قابل تنظیم است. مقادیر در دیتابیس ذخیره میشوند و بر مقادیر فایل پیکربندی اولویت دارند.
| Endpoint | Description |
|---|---|
/admin/settings/smtp_port |
SMTP server port |
/admin/settings/submission_port |
Submission server port |
/admin/settings/imap_port |
IMAP server port |
/admin/settings/turn_port |
TURN relay port |
/admin/settings/dovecot_port |
Dovecot SASL port |
/admin/settings/iroh_port |
Iroh relay port |
/admin/settings/ss_port |
Shadowsocks proxy port |
{"method": "POST", "resource": "/admin/settings/smtp_port",
"body": {"action": "set", "value": "2525"}, ...}
// Response
{"key": "__SMTP_PORT__", "value": "2525", "is_set": true}
Reset:
{"method": "POST", "resource": "/admin/settings/smtp_port",
"body": {"action": "reset"}, ...}
تنظیمات پیکربندی سرویسها مانند hostname، secret و URL از طریق همان الگوی set/reset قابل مدیریت هستند.
| Endpoint | Description |
|---|---|
/admin/settings/smtp_hostname |
SMTP server hostname |
/admin/settings/turn_realm |
TURN server realm |
/admin/settings/turn_secret |
TURN shared secret |
/admin/settings/turn_relay_ip |
TURN relay IP address |
/admin/settings/turn_ttl |
TURN credential TTL (seconds) |
/admin/settings/iroh_relay_url |
Iroh relay URL |
/admin/settings/ss_cipher |
Shadowsocks cipher algorithm |
/admin/settings/ss_password |
Shadowsocks password |
{"method": "POST", "resource": "/admin/settings/turn_secret",
"body": {"action": "set", "value": "my-shared-secret"}, ...}
Example — read Iroh relay URL:
// Request {"method": "GET", "resource": "/admin/settings/iroh_relay_url", ...} // Response {"key": "__IROH_RELAY_URL__", "value": "https://iroh.example.com", "is_set": true}
is_set: false باشد، به معنی استفاده از مقدار
پیشفرض فایل پیکربندی است.
با action: "reset" میتوانید هر تنظیمی را به مقدار پیشفرض بازگردانید.
لیست و حذف حسابهای کاربری. ایجاد حساب از طریق API امکانپذیر نیست (رمز عبورها هیچگاه از طریق API منتقل نمیشوند).
لیست تمام حسابها:// Request {"method": "GET", "resource": "/admin/accounts", ...} // Response { "status": 200, "body": { "total": 3, "accounts": [ {"username": "alice@example.com"}, {"username": "bob@example.com"}, {"username": "charlie@example.com"} ] } }حذف یک حساب:
// Request {"method": "DELETE", "resource": "/admin/accounts", "body": {"username": "alice@example.com"}, ...} // Response {"status": 200, "body": {"deleted": "alice@example.com"}}
مدیریت لیست نامهای کاربری مسدود. کاربران مسدود نمیتوانند از طریق /new یا JIT ثبتنام کنند.
حسابهای حذفشده بهطور خودکار به این لیست اضافه میشوند.
// Request {"method": "GET", "resource": "/admin/blocklist", ...} // Response { "status": 200, "body": { "total": 2, "blocked": [ { "username": "spammer@example.com", "reason": "deleted via admin panel", "blocked_at": "2026-02-18T15:30:00Z" } ] } }مسدود کردن یک کاربر:
{"method": "POST", "resource": "/admin/blocklist",
"body": {"username": "spammer@example.com", "reason": "abuse"}, ...}
رفع مسدودی:
{"method": "DELETE", "resource": "/admin/blocklist",
"body": {"username": "spammer@example.com"}, ...}
| Field | Type | Description |
|---|---|---|
username |
string | Blocked username (required) |
reason |
string | Reason for blocking (optional, default: "manually blocked") |
blocked_at |
string | RFC3339 timestamp (in GET responses only) |
/admin/accounts حذف میشود، نام کاربری
بهطور خودکار به لیست مسدودی اضافه میشود.
برای اجازه ثبتنام مجدد، ابتدا باید کاربر را از لیست مسدودی حذف کنید.
مدیریت سهمیه فضای ذخیرهسازی کاربران.
آمار کلی (بدون body):{
"status": 200,
"body": {
"total_storage_bytes": 1073741824,
"accounts_count": 42,
"default_quota_bytes": 107374182400
}
}
سهمیه یک کاربر خاص:
// Request {"method": "GET", "resource": "/admin/quota", "body": {"username": "alice@example.com"}, ...} // Response { "body": { "username": "alice@example.com", "used_bytes": 52428800, "max_bytes": 107374182400, "is_default": true } }تنظیم سهمیه اختصاصی:
// Set quota for one user (1GB) {"method": "PUT", "resource": "/admin/quota", "body": {"username": "alice@example.com", "max_bytes": 1073741824}, ...} // Set default quota for all users (2GB) {"method": "PUT", "resource": "/admin/quota", "body": {"max_bytes": 2147483648}, ...}بازنشانی سهمیه به پیشفرض:
{"method": "DELETE", "resource": "/admin/quota",
"body": {"username": "alice@example.com"}, ...}
پاکسازی پیامهای ذخیرهشده. فقط متد POST پشتیبانی میشود.
| Action | Description |
|---|---|
purge_user |
Delete all messages for a specific user (requires username) |
purge_all |
Delete ALL stored messages for all users |
purge_read |
Delete only read (Seen) messages for all users |
// Purge messages for one user {"method": "POST", "resource": "/admin/queue", "body": {"action": "purge_user", "username": "alice@example.com"}, ...} // Purge read messages for all users {"method": "POST", "resource": "/admin/queue", "body": {"action": "purge_read"}, ...} // Purge ALL messages {"method": "POST", "resource": "/admin/queue", "body": {"action": "purge_all"}, ...}
purge_all تمام ایمیلهای تمام کاربران در سرور را حذف
میکند.
حسابهای کاربری حفظ میشوند.
مدیریت لینکهای اشتراکگذاری مخاطبین (Contact Shares). فقط در صورت فعال بودن اشتراکگذاری در تنظیمات.
لیست:// GET Response { "body": { "total": 2, "shares": [ {"slug": "support", "url": "openpgp4fpr:ABCD...", "name": "Support Team"}, {"slug": "admin", "url": "openpgp4fpr:EFGH...", "name": "Admin"} ] } }ایجاد:
{"method": "POST", "resource": "/admin/shares",
"body": {
"slug": "support",
"url": "openpgp4fpr:ABCDEF123456...",
"name": "Support Team"
}, ...}
ویرایش:
{"method": "PUT", "resource": "/admin/shares",
"body": {
"slug": "support",
"name": "New Name"
}, ...}
حذف:
{"method": "DELETE", "resource": "/admin/shares",
"body": {"slug": "support"}, ...}
مدیریت قوانین بازنویسی DNS داخلی. این قوانین مسیر ارسال ایمیلها را تغییر میدهند.
لیست تمام قوانین:// GET Response { "body": { "total": 1, "overrides": [ { "lookup_key": "old-server.example.com", "target_host": "new-server.example.com", "comment": "migration in progress" } ] } }ایجاد یا ویرایش:
{"method": "POST", "resource": "/admin/dns",
"body": {
"lookup_key": "old.example.com",
"target_host": "10.0.0.5",
"comment": "Route to internal server"
}, ...}
حذف:
{"method": "DELETE", "resource": "/admin/dns",
"body": {"lookup_key": "old.example.com"}, ...}
تمام عملیاتهای Admin API از طریق یک رابط وب داخلی در مسیر /admin/ نیز قابل دسترسی هستند.
این پنل از همان توکن احراز هویت استفاده میکند.
| صفحه | امکانات |
|---|---|
| Overview | آمار سرور (کاربران، آپتایم، دیسک، ذخیرهسازی)، اتصالات فعال (IMAP، TURN، Shadowsocks)، نوار مصرف دیسک، دکمههای پاکسازی صف |
| Services | کلیدهای فعال/غیرفعال برای ثبتنام، JIT، TURN، Iroh، Shadowsocks و لاگ |
| Ports | مشاهده و تغییر شماره پورتها و تنظیمات پیکربندی |
| Accounts | لیست حسابها با مصرف فضا، حذف حساب (با پنجره تأیید) |
| Blocked | مشاهده کاربران مسدود شده، رفع مسدودیت (با پنجره تأیید) |
| DNS | مشاهده، افزودن، جستجو و حذف بازنویسیهای DNS (با پنجره تأیید) |
کدهای وضعیت داخلی (در فیلد status پاسخ JSON):
| Code | Meaning | When |
|---|---|---|
200 |
Success | Operation completed successfully |
201 |
Created | New resource created (DNS override, share) |
400 |
Bad Request | Missing required fields or invalid action |
401 |
Unauthorized | Missing, wrong, or rate-limited token |
404 |
Not Found | Unknown resource path or entry not found |
405 |
Method Not Allowed | Using wrong method for this resource |
500 |
Internal Error | Server-side failure (database, filesystem) |
503 |
Unavailable | Feature not enabled (e.g. sharing, DNS) |