diff --git a/main.go b/main.go
index 0e7fb31e..3914016d 100644
--- a/main.go
+++ b/main.go
@@ -466,8 +466,14 @@ func main() {
migrateDbCmd := flag.NewFlagSet("migrate-db", flag.ExitOnError)
var migrateDsn string
var migrateSrc string
+ var migrateDump string
+ var migrateRestore string
+ var migrateOut string
migrateDbCmd.StringVar(&migrateDsn, "dsn", "", "Destination PostgreSQL DSN (postgres://user:pass@host:port/db?sslmode=disable)")
migrateDbCmd.StringVar(&migrateSrc, "src", "", "Source SQLite file (defaults to the configured x-ui.db)")
+ migrateDbCmd.StringVar(&migrateDump, "dump", "", "Write a portable SQL text dump of --src to this file (.db -> .dump)")
+ migrateDbCmd.StringVar(&migrateRestore, "restore", "", "Rebuild a SQLite database from this SQL text dump (.dump -> .db); requires --out")
+ migrateDbCmd.StringVar(&migrateOut, "out", "", "Destination SQLite file for --restore (must not already exist)")
settingCmd := flag.NewFlagSet("setting", flag.ExitOnError)
var port int
@@ -512,7 +518,7 @@ func main() {
fmt.Println("Commands:")
fmt.Println(" run run web panel")
fmt.Println(" migrate migrate form other/old x-ui")
- fmt.Println(" migrate-db copy data from the SQLite file into a PostgreSQL database")
+ fmt.Println(" migrate-db SQLite <-> .dump (--dump/--restore) or copy into PostgreSQL (--dsn)")
fmt.Println(" setting set settings")
}
@@ -541,13 +547,30 @@ func main() {
if src == "" {
src = config.GetDBPath()
}
- if migrateDsn == "" {
- fmt.Println("--dsn is required: postgres://user:pass@host:port/dbname?sslmode=disable")
- return
- }
- if err := database.MigrateData(src, migrateDsn); err != nil {
- fmt.Println("migration failed:", err)
- os.Exit(1)
+ switch {
+ case migrateDump != "":
+ if err := database.DumpSQLite(src, migrateDump); err != nil {
+ fmt.Println("dump failed:", err)
+ os.Exit(1)
+ }
+ fmt.Printf("Dumped %s -> %s\n", src, migrateDump)
+ case migrateRestore != "":
+ if migrateOut == "" {
+ fmt.Println("--out is required when using --restore: the destination .db path (must not exist)")
+ return
+ }
+ if err := database.RestoreSQLite(migrateRestore, migrateOut); err != nil {
+ fmt.Println("restore failed:", err)
+ os.Exit(1)
+ }
+ fmt.Printf("Restored %s -> %s\n", migrateRestore, migrateOut)
+ case migrateDsn != "":
+ if err := database.MigrateData(src, migrateDsn); err != nil {
+ fmt.Println("migration failed:", err)
+ os.Exit(1)
+ }
+ default:
+ fmt.Println("nothing to do: pass --dump , --restore --out , or --dsn ")
}
case "setting":
err := settingCmd.Parse(os.Args[2:])
diff --git a/web/controller/server.go b/web/controller/server.go
index 6c70de74..3ea6fe88 100644
--- a/web/controller/server.go
+++ b/web/controller/server.go
@@ -53,6 +53,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
g.GET("/getPanelUpdateInfo", a.getPanelUpdateInfo)
g.GET("/getConfigJson", a.getConfigJson)
g.GET("/getDb", a.getDb)
+ g.GET("/getMigration", a.getMigration)
g.GET("/getNewUUID", a.getNewUUID)
g.GET("/getWebCertFiles", a.getWebCertFiles)
g.GET("/getNewX25519Cert", a.getNewX25519Cert)
@@ -300,6 +301,24 @@ func (a *ServerController) getDb(c *gin.Context) {
c.Writer.Write(db)
}
+// getMigration downloads a cross-engine migration file: a .dump on SQLite or a
+// .db SQLite database on PostgreSQL, so the data can seed the other backend.
+func (a *ServerController) getMigration(c *gin.Context) {
+ data, filename, err := a.serverService.GetMigration()
+ if err != nil {
+ jsonMsg(c, I18nWeb(c, "pages.index.getDatabaseError"), err)
+ return
+ }
+ if !filenameRegex.MatchString(filename) {
+ c.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid filename"))
+ return
+ }
+
+ c.Header("Content-Type", "application/octet-stream")
+ c.Header("Content-Disposition", "attachment; filename="+filename)
+ c.Writer.Write(data)
+}
+
// importDB imports a database file and restarts the Xray service.
func (a *ServerController) importDB(c *gin.Context) {
file, _, err := c.Request.FormFile("db")
diff --git a/web/service/server.go b/web/service/server.go
index dcbe5e51..6ec1fac8 100644
--- a/web/service/server.go
+++ b/web/service/server.go
@@ -1156,6 +1156,41 @@ func (s *ServerService) GetDb() ([]byte, error) {
return fileContents, nil
}
+// GetMigration produces a cross-engine migration file plus its filename: on a
+// SQLite panel it returns a portable .dump (SQL text), and on a PostgreSQL panel
+// it returns a .db SQLite database built from the live data. Either output can
+// then seed a panel running on the other backend.
+func (s *ServerService) GetMigration() ([]byte, string, error) {
+ if database.IsPostgres() {
+ tmp, err := os.CreateTemp("", "x-ui-migration-*.db")
+ if err != nil {
+ return nil, "", err
+ }
+ tmpPath := tmp.Name()
+ tmp.Close()
+ defer os.Remove(tmpPath)
+
+ if err := database.ExportPostgresToSQLite(config.GetDBDSN(), tmpPath); err != nil {
+ return nil, "", err
+ }
+ data, err := os.ReadFile(tmpPath)
+ if err != nil {
+ return nil, "", err
+ }
+ return data, "x-ui.db", nil
+ }
+
+ // SQLite panel: checkpoint so the .db reflects the latest writes, then dump.
+ if err := database.Checkpoint(); err != nil {
+ return nil, "", err
+ }
+ data, err := database.DumpSQLiteToBytes(config.GetDBPath())
+ if err != nil {
+ return nil, "", err
+ }
+ return data, "x-ui.dump", nil
+}
+
func (s *ServerService) ImportDB(file multipart.File) error {
if database.IsPostgres() {
return s.importPostgresDB(file)
diff --git a/web/translation/ar-EG.json b/web/translation/ar-EG.json
index 91290fc5..f7e25337 100644
--- a/web/translation/ar-EG.json
+++ b/web/translation/ar-EG.json
@@ -277,7 +277,10 @@
"getConfigError": "حدث خطأ أثناء استرجاع ملف الإعدادات",
"backupPostgresNote": "تعمل هذه اللوحة على PostgreSQL. يقوم «النسخ الاحتياطي» بتنزيل أرشيف pg_dump (.dump)، و«الاستعادة» تعيد تحميله عبر pg_restore. يجب أن تكون أدوات عميل PostgreSQL (pg_dump و pg_restore) مثبَّتة على الخادم.",
"exportDatabasePgDesc": "انقر لتنزيل نسخة PostgreSQL (.dump) من قاعدة بياناتك الحالية إلى جهازك.",
- "importDatabasePgDesc": "انقر لاختيار ورفع ملف .dump لاستعادة قاعدة بيانات PostgreSQL. سيؤدي هذا إلى استبدال جميع البيانات الحالية."
+ "importDatabasePgDesc": "انقر لاختيار ورفع ملف .dump لاستعادة قاعدة بيانات PostgreSQL. سيؤدي هذا إلى استبدال جميع البيانات الحالية.",
+ "migrationDownload": "تنزيل ملف الترحيل",
+ "migrationDownloadDesc": "انقر لتنزيل تصدير .dump محمول (نص SQL) لقاعدة بيانات SQLite الخاصة بك.",
+ "migrationDownloadPgDesc": "انقر لتنزيل قاعدة بيانات SQLite بامتداد .db مبنية من بيانات PostgreSQL الخاصة بك، جاهزة لتشغيل هذه اللوحة على SQLite."
},
"inbounds": {
"title": "الواردات",
diff --git a/web/translation/en-US.json b/web/translation/en-US.json
index a28c0894..443a8f0e 100644
--- a/web/translation/en-US.json
+++ b/web/translation/en-US.json
@@ -277,7 +277,10 @@
"getConfigError": "An error occurred while retrieving the config file.",
"backupPostgresNote": "This panel runs on PostgreSQL. Back Up downloads a pg_dump archive (.dump) and Restore loads it back with pg_restore. The server needs the PostgreSQL client tools (pg_dump and pg_restore) installed.",
"exportDatabasePgDesc": "Click to download a PostgreSQL dump (.dump) of your current database to your device.",
- "importDatabasePgDesc": "Click to select and upload a .dump file to restore your PostgreSQL database. This replaces all current data."
+ "importDatabasePgDesc": "Click to select and upload a .dump file to restore your PostgreSQL database. This replaces all current data.",
+ "migrationDownload": "Download Migration",
+ "migrationDownloadDesc": "Click to download a portable .dump (SQL text) export of your SQLite database.",
+ "migrationDownloadPgDesc": "Click to download a .db SQLite database built from your PostgreSQL data, ready to run this panel on SQLite."
},
"inbounds": {
"title": "Inbounds",
diff --git a/web/translation/es-ES.json b/web/translation/es-ES.json
index 0b9ba12c..2283e34a 100644
--- a/web/translation/es-ES.json
+++ b/web/translation/es-ES.json
@@ -277,7 +277,10 @@
"getConfigError": "Ocurrió un error al obtener el archivo de configuración",
"backupPostgresNote": "Este panel funciona con PostgreSQL. «Copia de seguridad» descarga un archivo pg_dump (.dump) y «Restaurar» lo vuelve a cargar con pg_restore. El servidor necesita tener instaladas las herramientas cliente de PostgreSQL (pg_dump y pg_restore).",
"exportDatabasePgDesc": "Haz clic para descargar un volcado de PostgreSQL (.dump) de tu base de datos actual en tu dispositivo.",
- "importDatabasePgDesc": "Haz clic para seleccionar y subir un archivo .dump y restaurar tu base de datos PostgreSQL. Esto reemplaza todos los datos actuales."
+ "importDatabasePgDesc": "Haz clic para seleccionar y subir un archivo .dump y restaurar tu base de datos PostgreSQL. Esto reemplaza todos los datos actuales.",
+ "migrationDownload": "Descargar migración",
+ "migrationDownloadDesc": "Haz clic para descargar una exportación portable .dump (texto SQL) de tu base de datos SQLite.",
+ "migrationDownloadPgDesc": "Haz clic para descargar una base de datos SQLite .db creada a partir de tus datos de PostgreSQL, lista para ejecutar este panel en SQLite."
},
"inbounds": {
"title": "Entradas",
diff --git a/web/translation/fa-IR.json b/web/translation/fa-IR.json
index 359a6de8..87f181f7 100644
--- a/web/translation/fa-IR.json
+++ b/web/translation/fa-IR.json
@@ -277,7 +277,10 @@
"getConfigError": "خطا در دریافت فایل پیکربندی",
"backupPostgresNote": "این پنل روی PostgreSQL اجرا میشود. «پشتیبانگیری» یک آرشیو pg_dump (.dump) دانلود میکند و «بازیابی» آن را با pg_restore بازمیگرداند. سرور باید ابزارهای کلاینت PostgreSQL (pg_dump و pg_restore) را نصب داشته باشد.",
"exportDatabasePgDesc": "برای دانلود یک دامپ PostgreSQL (.dump) از پایگاه داده فعلی روی دستگاهتان کلیک کنید.",
- "importDatabasePgDesc": "برای انتخاب و بارگذاری یک فایل .dump جهت بازیابی پایگاه داده PostgreSQL کلیک کنید. این کار همه دادههای فعلی را جایگزین میکند."
+ "importDatabasePgDesc": "برای انتخاب و بارگذاری یک فایل .dump جهت بازیابی پایگاه داده PostgreSQL کلیک کنید. این کار همه دادههای فعلی را جایگزین میکند.",
+ "migrationDownload": "دانلود فایل مهاجرت",
+ "migrationDownloadDesc": "برای دانلود یک خروجی قابلحمل .dump (متن SQL) از پایگاهدادهٔ SQLite خود کلیک کنید.",
+ "migrationDownloadPgDesc": "برای دانلود یک پایگاهدادهٔ SQLite با پسوند .db که از دادههای PostgreSQL شما ساخته میشود کلیک کنید؛ آمادهٔ اجرای این پنل روی SQLite."
},
"inbounds": {
"title": "ورودیها",
diff --git a/web/translation/id-ID.json b/web/translation/id-ID.json
index 6742f21f..523ad689 100644
--- a/web/translation/id-ID.json
+++ b/web/translation/id-ID.json
@@ -277,7 +277,10 @@
"getConfigError": "Terjadi kesalahan saat mengambil file konfigurasi",
"backupPostgresNote": "Panel ini berjalan di PostgreSQL. «Cadangkan» mengunduh arsip pg_dump (.dump) dan «Pulihkan» memuatnya kembali dengan pg_restore. Server memerlukan alat klien PostgreSQL (pg_dump dan pg_restore) terpasang.",
"exportDatabasePgDesc": "Klik untuk mengunduh dump PostgreSQL (.dump) dari basis data Anda saat ini ke perangkat Anda.",
- "importDatabasePgDesc": "Klik untuk memilih dan mengunggah berkas .dump guna memulihkan basis data PostgreSQL Anda. Ini menggantikan semua data saat ini."
+ "importDatabasePgDesc": "Klik untuk memilih dan mengunggah berkas .dump guna memulihkan basis data PostgreSQL Anda. Ini menggantikan semua data saat ini.",
+ "migrationDownload": "Unduh migrasi",
+ "migrationDownloadDesc": "Klik untuk mengunduh ekspor .dump (teks SQL) portabel dari basis data SQLite Anda.",
+ "migrationDownloadPgDesc": "Klik untuk mengunduh basis data SQLite .db yang dibuat dari data PostgreSQL Anda, siap menjalankan panel ini di SQLite."
},
"inbounds": {
"title": "Inbound",
diff --git a/web/translation/ja-JP.json b/web/translation/ja-JP.json
index 7397e12a..8cc74116 100644
--- a/web/translation/ja-JP.json
+++ b/web/translation/ja-JP.json
@@ -277,7 +277,10 @@
"getConfigError": "設定ファイルの取得中にエラーが発生しました",
"backupPostgresNote": "このパネルは PostgreSQL で動作しています。「バックアップ」は pg_dump アーカイブ (.dump) をダウンロードし、「復元」は pg_restore で読み込み直します。サーバーに PostgreSQL クライアントツール (pg_dump と pg_restore) がインストールされている必要があります。",
"exportDatabasePgDesc": "現在のデータベースの PostgreSQL ダンプ (.dump) を端末にダウンロードするにはクリックしてください。",
- "importDatabasePgDesc": "PostgreSQL データベースを復元するために .dump ファイルを選択してアップロードするにはクリックしてください。現在のすべてのデータが置き換えられます。"
+ "importDatabasePgDesc": "PostgreSQL データベースを復元するために .dump ファイルを選択してアップロードするにはクリックしてください。現在のすべてのデータが置き換えられます。",
+ "migrationDownload": "移行ファイルをダウンロード",
+ "migrationDownloadDesc": "SQLite データベースのポータブルな .dump(SQL テキスト)エクスポートをダウンロードするにはクリックします。",
+ "migrationDownloadPgDesc": "PostgreSQL のデータから作成した .db SQLite データベースをダウンロードします。このパネルを SQLite で実行する準備が整います。"
},
"inbounds": {
"title": "インバウンド",
diff --git a/web/translation/pt-BR.json b/web/translation/pt-BR.json
index 955df690..7bc5a7ef 100644
--- a/web/translation/pt-BR.json
+++ b/web/translation/pt-BR.json
@@ -277,7 +277,10 @@
"getConfigError": "Ocorreu um erro ao recuperar o arquivo de configuração",
"backupPostgresNote": "Este painel é executado em PostgreSQL. «Backup» baixa um arquivo pg_dump (.dump) e «Restaurar» o recarrega com pg_restore. O servidor precisa ter as ferramentas cliente do PostgreSQL (pg_dump e pg_restore) instaladas.",
"exportDatabasePgDesc": "Clique para baixar um dump do PostgreSQL (.dump) do seu banco de dados atual para o seu dispositivo.",
- "importDatabasePgDesc": "Clique para selecionar e enviar um arquivo .dump para restaurar seu banco de dados PostgreSQL. Isso substitui todos os dados atuais."
+ "importDatabasePgDesc": "Clique para selecionar e enviar um arquivo .dump para restaurar seu banco de dados PostgreSQL. Isso substitui todos os dados atuais.",
+ "migrationDownload": "Baixar migração",
+ "migrationDownloadDesc": "Clique para baixar uma exportação portátil .dump (texto SQL) do seu banco de dados SQLite.",
+ "migrationDownloadPgDesc": "Clique para baixar um banco de dados SQLite .db criado a partir dos seus dados do PostgreSQL, pronto para executar este painel no SQLite."
},
"inbounds": {
"title": "Entradas",
diff --git a/web/translation/ru-RU.json b/web/translation/ru-RU.json
index 32b0e436..226df950 100644
--- a/web/translation/ru-RU.json
+++ b/web/translation/ru-RU.json
@@ -277,7 +277,10 @@
"getConfigError": "Произошла ошибка при получении конфигурационного файла",
"backupPostgresNote": "Эта панель работает на PostgreSQL. «Резервная копия» скачивает архив pg_dump (.dump), а «Восстановление» загружает его обратно через pg_restore. На сервере должны быть установлены клиентские инструменты PostgreSQL (pg_dump и pg_restore).",
"exportDatabasePgDesc": "Нажмите, чтобы скачать дамп PostgreSQL (.dump) текущей базы данных на ваше устройство.",
- "importDatabasePgDesc": "Нажмите, чтобы выбрать и загрузить файл .dump для восстановления базы данных PostgreSQL. Это заменит все текущие данные."
+ "importDatabasePgDesc": "Нажмите, чтобы выбрать и загрузить файл .dump для восстановления базы данных PostgreSQL. Это заменит все текущие данные.",
+ "migrationDownload": "Скачать файл миграции",
+ "migrationDownloadDesc": "Нажмите, чтобы скачать переносимый экспорт .dump (текст SQL) вашей базы данных SQLite.",
+ "migrationDownloadPgDesc": "Нажмите, чтобы скачать базу данных SQLite (.db), собранную из ваших данных PostgreSQL и готовую для запуска панели на SQLite."
},
"inbounds": {
"title": "Входящие",
diff --git a/web/translation/tr-TR.json b/web/translation/tr-TR.json
index e78f55ab..69b52e5e 100644
--- a/web/translation/tr-TR.json
+++ b/web/translation/tr-TR.json
@@ -277,7 +277,10 @@
"getConfigError": "Yapılandırma dosyası alınırken bir hata oluştu",
"backupPostgresNote": "Bu panel PostgreSQL üzerinde çalışıyor. «Yedekle» bir pg_dump arşivi (.dump) indirir, «Geri Yükle» ise onu pg_restore ile geri yükler. Sunucuda PostgreSQL istemci araçlarının (pg_dump ve pg_restore) kurulu olması gerekir.",
"exportDatabasePgDesc": "Mevcut veritabanınızın PostgreSQL dökümünü (.dump) cihazınıza indirmek için tıklayın.",
- "importDatabasePgDesc": "PostgreSQL veritabanınızı geri yüklemek için bir .dump dosyası seçip yüklemek üzere tıklayın. Bu, tüm mevcut verilerin yerini alır."
+ "importDatabasePgDesc": "PostgreSQL veritabanınızı geri yüklemek için bir .dump dosyası seçip yüklemek üzere tıklayın. Bu, tüm mevcut verilerin yerini alır.",
+ "migrationDownload": "Geçiş dosyasını indir",
+ "migrationDownloadDesc": "SQLite veritabanınızın taşınabilir .dump (SQL metni) dışa aktarımını indirmek için tıklayın.",
+ "migrationDownloadPgDesc": "PostgreSQL verilerinizden oluşturulan ve bu paneli SQLite üzerinde çalıştırmaya hazır bir .db SQLite veritabanı indirmek için tıklayın."
},
"inbounds": {
"title": "Gelenler",
diff --git a/web/translation/uk-UA.json b/web/translation/uk-UA.json
index 4d9974d8..b386306a 100644
--- a/web/translation/uk-UA.json
+++ b/web/translation/uk-UA.json
@@ -277,7 +277,10 @@
"getConfigError": "Виникла помилка під час отримання файлу конфігурації",
"backupPostgresNote": "Ця панель працює на PostgreSQL. «Резервна копія» завантажує архів pg_dump (.dump), а «Відновлення» завантажує його назад через pg_restore. На сервері мають бути встановлені клієнтські інструменти PostgreSQL (pg_dump і pg_restore).",
"exportDatabasePgDesc": "Натисніть, щоб завантажити дамп PostgreSQL (.dump) вашої поточної бази даних на ваш пристрій.",
- "importDatabasePgDesc": "Натисніть, щоб вибрати та завантажити файл .dump для відновлення бази даних PostgreSQL. Це замінить усі поточні дані."
+ "importDatabasePgDesc": "Натисніть, щоб вибрати та завантажити файл .dump для відновлення бази даних PostgreSQL. Це замінить усі поточні дані.",
+ "migrationDownload": "Завантажити файл міграції",
+ "migrationDownloadDesc": "Натисніть, щоб завантажити переносний експорт .dump (текст SQL) вашої бази даних SQLite.",
+ "migrationDownloadPgDesc": "Натисніть, щоб завантажити базу даних SQLite (.db), створену з ваших даних PostgreSQL і готову для запуску панелі на SQLite."
},
"inbounds": {
"title": "Вхідні",
diff --git a/web/translation/vi-VN.json b/web/translation/vi-VN.json
index 66b2693e..12c620af 100644
--- a/web/translation/vi-VN.json
+++ b/web/translation/vi-VN.json
@@ -277,7 +277,10 @@
"getConfigError": "Lỗi xảy ra khi truy xuất tệp cấu hình",
"backupPostgresNote": "Bảng điều khiển này chạy trên PostgreSQL. «Sao lưu» tải xuống một tệp lưu trữ pg_dump (.dump) và «Khôi phục» nạp lại bằng pg_restore. Máy chủ cần cài đặt các công cụ máy khách PostgreSQL (pg_dump và pg_restore).",
"exportDatabasePgDesc": "Nhấn để tải xuống bản kết xuất PostgreSQL (.dump) của cơ sở dữ liệu hiện tại về thiết bị của bạn.",
- "importDatabasePgDesc": "Nhấn để chọn và tải lên một tệp .dump nhằm khôi phục cơ sở dữ liệu PostgreSQL của bạn. Thao tác này sẽ thay thế toàn bộ dữ liệu hiện tại."
+ "importDatabasePgDesc": "Nhấn để chọn và tải lên một tệp .dump nhằm khôi phục cơ sở dữ liệu PostgreSQL của bạn. Thao tác này sẽ thay thế toàn bộ dữ liệu hiện tại.",
+ "migrationDownload": "Tải tệp di trú",
+ "migrationDownloadDesc": "Nhấp để tải xuống bản xuất .dump (văn bản SQL) di động của cơ sở dữ liệu SQLite của bạn.",
+ "migrationDownloadPgDesc": "Nhấp để tải xuống cơ sở dữ liệu SQLite .db được tạo từ dữ liệu PostgreSQL của bạn, sẵn sàng chạy bảng điều khiển này trên SQLite."
},
"inbounds": {
"title": "Inbound",
diff --git a/web/translation/zh-CN.json b/web/translation/zh-CN.json
index cbd9aea6..d7076703 100644
--- a/web/translation/zh-CN.json
+++ b/web/translation/zh-CN.json
@@ -277,7 +277,10 @@
"getConfigError": "检索配置文件时出错",
"backupPostgresNote": "此面板运行在 PostgreSQL 上。「备份」会下载一个 pg_dump 归档(.dump),「恢复」会通过 pg_restore 重新载入。服务器需要安装 PostgreSQL 客户端工具(pg_dump 和 pg_restore)。",
"exportDatabasePgDesc": "点击将当前数据库的 PostgreSQL 转储(.dump)下载到您的设备。",
- "importDatabasePgDesc": "点击选择并上传 .dump 文件以恢复您的 PostgreSQL 数据库。此操作将替换所有当前数据。"
+ "importDatabasePgDesc": "点击选择并上传 .dump 文件以恢复您的 PostgreSQL 数据库。此操作将替换所有当前数据。",
+ "migrationDownload": "下载迁移文件",
+ "migrationDownloadDesc": "点击下载当前 SQLite 数据库的可移植 .dump(SQL 文本)导出文件。",
+ "migrationDownloadPgDesc": "点击下载由 PostgreSQL 数据构建的 .db SQLite 数据库,可用于在 SQLite 上运行本面板。"
},
"inbounds": {
"title": "入站",
diff --git a/web/translation/zh-TW.json b/web/translation/zh-TW.json
index c3422480..813f53c2 100644
--- a/web/translation/zh-TW.json
+++ b/web/translation/zh-TW.json
@@ -277,7 +277,10 @@
"getConfigError": "檢索設定檔時發生錯誤",
"backupPostgresNote": "此面板執行於 PostgreSQL 上。「備份」會下載一個 pg_dump 封存檔(.dump),「還原」會透過 pg_restore 重新載入。伺服器需要安裝 PostgreSQL 用戶端工具(pg_dump 與 pg_restore)。",
"exportDatabasePgDesc": "點擊將目前資料庫的 PostgreSQL 傾印(.dump)下載到您的裝置。",
- "importDatabasePgDesc": "點擊選擇並上傳 .dump 檔案以還原您的 PostgreSQL 資料庫。此操作將取代所有目前的資料。"
+ "importDatabasePgDesc": "點擊選擇並上傳 .dump 檔案以還原您的 PostgreSQL 資料庫。此操作將取代所有目前的資料。",
+ "migrationDownload": "下載遷移檔案",
+ "migrationDownloadDesc": "點擊下載目前 SQLite 資料庫的可攜式 .dump(SQL 文字)匯出檔。",
+ "migrationDownloadPgDesc": "點擊下載由 PostgreSQL 資料建立的 .db SQLite 資料庫,可用於在 SQLite 上執行本面板。"
},
"inbounds": {
"title": "入站",
diff --git a/x-ui.sh b/x-ui.sh
index c2e033cc..a9a986f8 100644
--- a/x-ui.sh
+++ b/x-ui.sh
@@ -2690,7 +2690,7 @@ migrate_to_postgres() {
echo ""
echo -e "${yellow}This copies your current SQLite data into a PostgreSQL database,${plain}"
echo -e "${yellow}then switches the panel to PostgreSQL and restarts it.${plain}"
- echo -e "${yellow}The destination PostgreSQL database must be empty.${plain}"
+ echo -e "${red}Any existing panel tables in the destination will be cleared and overwritten.${plain}"
confirm "Continue?" "n" || return 0
local dsn="" pg_mode