Browse Source

Merge pull request #977 from 0xJacky/feat/docker-ui-only

feat: manage nginx in another docker container
Jacky 3 months ago
parent
commit
ea90da43f7
90 changed files with 2363 additions and 572 deletions
  1. 23 0
      .devcontainer/docker-compose.yml
  2. 1 1
      .devcontainer/init-nginx.sh
  3. 1 1
      .devcontainer/start.sh
  4. 6 1
      api/config/add.go
  5. 21 4
      api/nginx/control.go
  6. 1 1
      api/nginx/router.go
  7. 6 3
      api/nginx/status.go
  8. 1 0
      api/settings/settings.go
  9. 1 0
      app/src/api/settings.ts
  10. 3 0
      app/src/components/Breadcrumb/index.ts
  11. 62 3
      app/src/components/CodeEditor/CodeCompletion.ts
  12. 3 0
      app/src/components/EnvGroupTabs/index.ts
  13. 3 0
      app/src/components/EnvIndicator/index.ts
  14. 3 0
      app/src/components/ICP/index.ts
  15. 3 0
      app/src/components/Logo/index.ts
  16. 3 0
      app/src/components/NginxControl/index.ts
  17. 3 0
      app/src/components/NodeSelector/index.ts
  18. 3 0
      app/src/components/Notification/index.ts
  19. 3 0
      app/src/components/OTPInput/index.ts
  20. 3 0
      app/src/components/PageHeader/index.ts
  21. 3 0
      app/src/components/ReactiveFromNow/index.ts
  22. 3 0
      app/src/components/SensitiveString/index.ts
  23. 3 0
      app/src/components/SetLanguage/index.ts
  24. 1 1
      app/src/components/SwitchAppearance/SwitchAppearance.vue
  25. 3 0
      app/src/components/SwitchAppearance/index.ts
  26. 3 0
      app/src/components/SystemRestore/index.ts
  27. 8 0
      app/src/components/TwoFA/index.ts
  28. 3 0
      app/src/components/VPSwitch/index.ts
  29. 15 0
      app/src/constants/errors/docker.ts
  30. 1 0
      app/src/constants/errors/nginx.ts
  31. 87 21
      app/src/language/ar/app.po
  32. 88 22
      app/src/language/de_DE/app.po
  33. 87 22
      app/src/language/en/app.po
  34. 87 21
      app/src/language/es/app.po
  35. 86 21
      app/src/language/fr_FR/app.po
  36. 87 22
      app/src/language/ko_KR/app.po
  37. 73 21
      app/src/language/messages.pot
  38. 87 21
      app/src/language/ru_RU/app.po
  39. 87 21
      app/src/language/tr_TR/app.po
  40. 73 21
      app/src/language/uk_UA/app.po
  41. 87 22
      app/src/language/vi_VN/app.po
  42. 87 32
      app/src/language/zh_CN/app.po
  43. 87 21
      app/src/language/zh_TW/app.po
  44. 19 133
      app/src/views/preference/Preference.vue
  45. 0 0
      app/src/views/preference/components/AuthSettings/AddPasskey.vue
  46. 2 2
      app/src/views/preference/components/AuthSettings/Passkey.vue
  47. 1 1
      app/src/views/preference/components/AuthSettings/RecoveryCodes.vue
  48. 2 2
      app/src/views/preference/components/AuthSettings/TOTP.vue
  49. 11 0
      app/src/views/preference/components/AuthSettings/index.ts
  50. 127 0
      app/src/views/preference/store/index.ts
  51. 4 3
      app/src/views/preference/tabs/AppSettings.vue
  52. 6 6
      app/src/views/preference/tabs/AuthSettings.vue
  53. 3 3
      app/src/views/preference/tabs/CertSettings.vue
  54. 2 2
      app/src/views/preference/tabs/ExternalNotify.vue
  55. 3 3
      app/src/views/preference/tabs/HTTPSettings.vue
  56. 3 2
      app/src/views/preference/tabs/LogrotateSettings.vue
  57. 16 2
      app/src/views/preference/tabs/NginxSettings.vue
  58. 4 4
      app/src/views/preference/tabs/NodeSettings.vue
  59. 3 3
      app/src/views/preference/tabs/OpenAISettings.vue
  60. 3 2
      app/src/views/preference/tabs/ServerSettings.vue
  61. 3 2
      app/src/views/preference/tabs/TerminalSettings.vue
  62. 11 0
      app/src/views/preference/tabs/index.ts
  63. 20 6
      docs/guide/config-nginx.md
  64. 18 4
      docs/zh_CN/guide/config-nginx.md
  65. 20 4
      docs/zh_TW/guide/config-nginx.md
  66. 13 0
      go.mod
  67. 37 9
      go.sum
  68. 3 2
      internal/cmd/main.go
  69. 23 0
      internal/cmd/upgrade_docker.go
  70. 5 1
      internal/config/save.go
  71. 22 0
      internal/docker/docker.go
  72. 20 0
      internal/docker/errors.go
  73. 80 0
      internal/docker/exec.go
  74. 329 0
      internal/docker/ota.go
  75. 29 0
      internal/docker/stat_path.go
  76. 58 0
      internal/docker/status.go
  77. 13 0
      internal/kernel/boot.go
  78. 1 0
      internal/nginx/errors.go
  79. 28 0
      internal/nginx/exec.go
  80. 38 51
      internal/nginx/nginx.go
  81. 4 1
      internal/site/disable.go
  82. 8 2
      internal/site/enable.go
  83. 16 4
      internal/site/maintenance.go
  84. 13 6
      internal/site/rename.go
  85. 9 2
      internal/site/save.go
  86. 4 1
      internal/stream/disable.go
  87. 8 2
      internal/stream/enable.go
  88. 8 2
      internal/stream/rename.go
  89. 9 2
      internal/stream/save.go
  90. 5 0
      settings/nginx.go

+ 23 - 0
.devcontainer/docker-compose.yml

@@ -7,6 +7,7 @@ services:
       - ../..:/workspaces:cached
       - ../..:/workspaces:cached
       - ./go-path:/root/go
       - ./go-path:/root/go
       - ./data/nginx:/etc/nginx
       - ./data/nginx:/etc/nginx
+      - /var/run/docker.sock:/var/run/docker.sock
     command: sleep infinity
     command: sleep infinity
     environment:
     environment:
       - NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
       - NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
@@ -25,6 +26,28 @@ services:
       - nginx-ui
       - nginx-ui
     networks:
     networks:
       nginxui:
       nginxui:
+  nginx-ui-3:
+    image: nginx-ui-dev
+    container_name: nginx-ui-3
+    volumes:
+      - ../..:/workspaces:cached
+      - ./data/nginx-ui-3/nginx:/etc/nginx
+      - ./data/nginx-ui-3/nginx-ui:/etc/nginx-ui
+      - /var/run/docker.sock:/var/run/docker.sock
+    working_dir: /workspaces/nginx-ui
+    command: ./.devcontainer/node-supervisor.sh
+    depends_on:
+      - nginx-ui
+    networks:
+      nginxui:
+  nginx:
+    image: nginx-ui-dev
+    container_name: nginx
+    volumes:
+      - ./data/nginx-ui-3/nginx:/etc/nginx
+    command: sleep infinity
+    networks:
+      nginxui:
   pebble:
   pebble:
     image: ghcr.io/letsencrypt/pebble:latest
     image: ghcr.io/letsencrypt/pebble:latest
     volumes:
     volumes:

+ 1 - 1
.devcontainer/init-nginx.sh

@@ -6,4 +6,4 @@ if [ "$(ls -A /etc/nginx)" = "" ]; then
 fi
 fi
 
 
 # start nginx
 # start nginx
-nginx -g "daemon off;"
+nginx

+ 1 - 1
.devcontainer/start.sh

@@ -3,7 +3,7 @@
 # install air
 # install air
 go install github.com/air-verse/air@latest
 go install github.com/air-verse/air@latest
 
 
-# install zsh-autosuggestions
+install zsh-autosuggestions
 git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
 git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
 
 
 if ! grep -q "zsh-autosuggestions" ~/.zshrc; then
 if ! grep -q "zsh-autosuggestions" ~/.zshrc; then

+ 6 - 1
api/config/add.go

@@ -74,7 +74,12 @@ func AddConfig(c *gin.Context) {
 		return
 		return
 	}
 	}
 
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
+
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 		cosy.ErrHandler(c, cosy.WrapErrorWithParams(config.ErrNginxReloadFailed, output))
 		cosy.ErrHandler(c, cosy.WrapErrorWithParams(config.ErrNginxReloadFailed, output))
 		return
 		return

+ 21 - 4
api/nginx/control.go

@@ -5,24 +5,36 @@ import (
 
 
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
 )
 )
 
 
+// Reload reloads the nginx
 func Reload(c *gin.Context) {
 func Reload(c *gin.Context) {
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
 		"message": output,
 		"message": output,
 		"level":   nginx.GetLogLevel(output),
 		"level":   nginx.GetLogLevel(output),
 	})
 	})
 }
 }
 
 
-func Test(c *gin.Context) {
-	output := nginx.TestConf()
+// TestConfig tests the nginx config
+func TestConfig(c *gin.Context) {
+	output, err := nginx.TestConfig()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
 		"message": output,
 		"message": output,
 		"level":   nginx.GetLogLevel(output),
 		"level":   nginx.GetLogLevel(output),
 	})
 	})
 }
 }
 
 
+// Restart restarts the nginx
 func Restart(c *gin.Context) {
 func Restart(c *gin.Context) {
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
 		"message": "ok",
 		"message": "ok",
@@ -30,8 +42,13 @@ func Restart(c *gin.Context) {
 	go nginx.Restart()
 	go nginx.Restart()
 }
 }
 
 
+// Status returns the status of the nginx
 func Status(c *gin.Context) {
 func Status(c *gin.Context) {
-	lastOutput := nginx.GetLastOutput()
+	lastOutput, err := nginx.GetLastOutput()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 
 
 	running := nginx.IsNginxRunning()
 	running := nginx.IsNginxRunning()
 
 

+ 1 - 1
api/nginx/router.go

@@ -11,7 +11,7 @@ func InitRouter(r *gin.RouterGroup) {
 	r.POST("ngx/format_code", FormatNginxConfig)
 	r.POST("ngx/format_code", FormatNginxConfig)
 	r.POST("nginx/reload", Reload)
 	r.POST("nginx/reload", Reload)
 	r.POST("nginx/restart", Restart)
 	r.POST("nginx/restart", Restart)
-	r.POST("nginx/test", Test)
+	r.POST("nginx/test", TestConfig)
 	r.GET("nginx/status", Status)
 	r.GET("nginx/status", Status)
 	// Get detailed Nginx status information, including connection count, process information, etc. (Issue #850)
 	// Get detailed Nginx status information, including connection count, process information, etc. (Issue #850)
 	r.GET("nginx/detail_status", GetDetailStatus)
 	r.GET("nginx/detail_status", GetDetailStatus)

+ 6 - 3
api/nginx/status.go

@@ -4,7 +4,6 @@
 package nginx
 package nginx
 
 
 import (
 import (
-	"errors"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 	"time"
 	"time"
@@ -119,10 +118,14 @@ func ToggleStubStatus(c *gin.Context) {
 	}
 	}
 
 
 	// Reload Nginx configuration
 	// Reload Nginx configuration
-	reloadOutput := nginx.Reload()
+	reloadOutput, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
 	if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
 		strings.Contains(strings.ToLower(reloadOutput), "failed")) {
 		strings.Contains(strings.ToLower(reloadOutput), "failed")) {
-		cosy.ErrHandler(c, errors.New("Reload Nginx failed"))
+		cosy.ErrHandler(c, cosy.WrapErrorWithParams(nginx.ErrReloadFailed, reloadOutput))
 		return
 		return
 	}
 	}
 
 

+ 1 - 0
api/settings/settings.go

@@ -25,6 +25,7 @@ func GetSettings(c *gin.Context) {
 	settings.NginxSettings.ErrorLogPath = nginx.GetErrorLogPath()
 	settings.NginxSettings.ErrorLogPath = nginx.GetErrorLogPath()
 	settings.NginxSettings.ConfigDir = nginx.GetConfPath()
 	settings.NginxSettings.ConfigDir = nginx.GetConfPath()
 	settings.NginxSettings.PIDPath = nginx.GetPIDPath()
 	settings.NginxSettings.PIDPath = nginx.GetPIDPath()
+	settings.NginxSettings.StubStatusPort = settings.NginxSettings.GetStubStatusPort()
 
 
 	if settings.NginxSettings.ReloadCmd == "" {
 	if settings.NginxSettings.ReloadCmd == "" {
 		settings.NginxSettings.ReloadCmd = "nginx -s reload"
 		settings.NginxSettings.ReloadCmd = "nginx -s reload"

+ 1 - 0
app/src/api/settings.ts

@@ -64,6 +64,7 @@ export interface NginxSettings {
   reload_cmd: string
   reload_cmd: string
   restart_cmd: string
   restart_cmd: string
   stub_status_port: number
   stub_status_port: number
+  container_name: string
 }
 }
 
 
 export interface NodeSettings {
 export interface NodeSettings {

+ 3 - 0
app/src/components/Breadcrumb/index.ts

@@ -0,0 +1,3 @@
+import Breadcrumb from './Breadcrumb.vue'
+
+export default Breadcrumb

+ 62 - 3
app/src/components/CodeEditor/CodeCompletion.ts

@@ -12,12 +12,39 @@ function debug(...args: any[]) {
   }
   }
 }
 }
 
 
+// Config file patterns and extensions
+const CONFIG_FILE_EXTENSIONS = ['.conf', '.config']
+const SENSITIVE_CONTENT_PATTERNS = [
+  /-----BEGIN [A-Z ]+ PRIVATE KEY-----/,
+  /-----BEGIN CERTIFICATE-----/,
+  /apiKey\s*[:=]\s*["'][a-zA-Z0-9]+["']/,
+  /password\s*[:=]\s*["'][^"']+["']/,
+  /secret\s*[:=]\s*["'][^"']+["']/,
+]
+
 function useCodeCompletion() {
 function useCodeCompletion() {
   const editorRef = ref<Editor>()
   const editorRef = ref<Editor>()
   const currentGhostText = ref<string>('')
   const currentGhostText = ref<string>('')
+  const isConfigFile = ref<boolean>(false)
 
 
   const ws = openai.code_completion()
   const ws = openai.code_completion()
 
 
+  // Check if the current file is a configuration file
+  function checkIfConfigFile(filename: string, content: string): boolean {
+    // Check file extension
+    const hasConfigExtension = CONFIG_FILE_EXTENSIONS.some(ext => filename.toLowerCase().endsWith(ext))
+
+    // Check if it's an Nginx configuration file based on common patterns
+    const hasNginxPatterns = /server\s*\{|location\s*\/|http\s*\{|upstream\s*[\w-]+\s*\{/.test(content)
+
+    return hasConfigExtension || hasNginxPatterns
+  }
+
+  // Check if content contains sensitive information that shouldn't be sent
+  function containsSensitiveContent(content: string): boolean {
+    return SENSITIVE_CONTENT_PATTERNS.some(pattern => pattern.test(content))
+  }
+
   function getAISuggestions(code: string, context: string, position: Point, callback: (suggestion: string) => void, language: string = 'nginx', suffix: string = '', requestId: string) {
   function getAISuggestions(code: string, context: string, position: Point, callback: (suggestion: string) => void, language: string = 'nginx', suffix: string = '', requestId: string) {
     if (!ws || ws.readyState !== WebSocket.OPEN) {
     if (!ws || ws.readyState !== WebSocket.OPEN) {
       debug('WebSocket is not open')
       debug('WebSocket is not open')
@@ -29,6 +56,17 @@ function useCodeCompletion() {
       return
       return
     }
     }
 
 
+    // Skip if not a config file or contains sensitive content
+    if (!isConfigFile.value) {
+      debug('Skipping AI suggestions for non-config file')
+      return
+    }
+
+    if (containsSensitiveContent(context)) {
+      debug('Skipping AI suggestions due to sensitive content')
+      return
+    }
+
     const message = {
     const message = {
       context,
       context,
       code,
       code,
@@ -57,8 +95,20 @@ function useCodeCompletion() {
       return
       return
     }
     }
 
 
+    if (!isConfigFile.value) {
+      debug('Skipping ghost text for non-config file')
+      return
+    }
+
     try {
     try {
       const currentText = editorRef.value.getValue()
       const currentText = editorRef.value.getValue()
+
+      // Skip if content contains sensitive information
+      if (containsSensitiveContent(currentText)) {
+        debug('Skipping ghost text due to sensitive content')
+        return
+      }
+
       const cursorPosition = editorRef.value.getCursorPosition()
       const cursorPosition = editorRef.value.getCursorPosition()
 
 
       // Get all text before the current cursor position as the code part for the request
       // Get all text before the current cursor position as the code part for the request
@@ -175,7 +225,7 @@ function useCodeCompletion() {
 
 
   debug('Editor initialized')
   debug('Editor initialized')
 
 
-  async function init(editor: Editor) {
+  async function init(editor: Editor, filename: string = '') {
     const { enabled } = await openai.get_code_completion_enabled_status()
     const { enabled } = await openai.get_code_completion_enabled_status()
     if (!enabled) {
     if (!enabled) {
       debug('Code completion is not enabled')
       debug('Code completion is not enabled')
@@ -184,6 +234,11 @@ function useCodeCompletion() {
 
 
     editorRef.value = editor
     editorRef.value = editor
 
 
+    // Determine if the current file is a configuration file
+    const content = editor.getValue()
+    isConfigFile.value = checkIfConfigFile(filename, content)
+    debug(`File type check: isConfigFile=${isConfigFile.value}, filename=${filename}`)
+
     // Set up Tab key handler
     // Set up Tab key handler
     setupTabHandler(editor)
     setupTabHandler(editor)
 
 
@@ -195,7 +250,9 @@ function useCodeCompletion() {
 
 
         if (e.action === 'insert' || e.action === 'remove') {
         if (e.action === 'insert' || e.action === 'remove') {
           // Clear current ghost text
           // Clear current ghost text
-          debouncedApplyGhostText()
+          if (isConfigFile.value) {
+            debouncedApplyGhostText()
+          }
         }
         }
       })
       })
 
 
@@ -203,7 +260,9 @@ function useCodeCompletion() {
       editor.selection.on('changeCursor', () => {
       editor.selection.on('changeCursor', () => {
         debug('Cursor changed')
         debug('Cursor changed')
         clearGhostText()
         clearGhostText()
-        debouncedApplyGhostText()
+        if (isConfigFile.value) {
+          debouncedApplyGhostText()
+        }
       })
       })
     }, 2000)
     }, 2000)
   }
   }

+ 3 - 0
app/src/components/EnvGroupTabs/index.ts

@@ -0,0 +1,3 @@
+import EnvGroupTabs from './EnvGroupTabs.vue'
+
+export default EnvGroupTabs

+ 3 - 0
app/src/components/EnvIndicator/index.ts

@@ -0,0 +1,3 @@
+import EnvIndicator from './EnvIndicator.vue'
+
+export default EnvIndicator

+ 3 - 0
app/src/components/ICP/index.ts

@@ -0,0 +1,3 @@
+import ICP from './ICP.vue'
+
+export default ICP

+ 3 - 0
app/src/components/Logo/index.ts

@@ -0,0 +1,3 @@
+import Logo from './Logo.vue'
+
+export default Logo

+ 3 - 0
app/src/components/NginxControl/index.ts

@@ -0,0 +1,3 @@
+import NginxControl from './NginxControl.vue'
+
+export default NginxControl

+ 3 - 0
app/src/components/NodeSelector/index.ts

@@ -0,0 +1,3 @@
+import NodeSelector from './NodeSelector.vue'
+
+export default NodeSelector

+ 3 - 0
app/src/components/Notification/index.ts

@@ -0,0 +1,3 @@
+import Notification from './Notification.vue'
+
+export default Notification

+ 3 - 0
app/src/components/OTPInput/index.ts

@@ -0,0 +1,3 @@
+import OTPInput from './OTPInput.vue'
+
+export default OTPInput

+ 3 - 0
app/src/components/PageHeader/index.ts

@@ -0,0 +1,3 @@
+import PageHeader from './PageHeader.vue'
+
+export default PageHeader

+ 3 - 0
app/src/components/ReactiveFromNow/index.ts

@@ -0,0 +1,3 @@
+import ReactiveFromNow from './ReactiveFromNow.vue'
+
+export default ReactiveFromNow

+ 3 - 0
app/src/components/SensitiveString/index.ts

@@ -0,0 +1,3 @@
+import SensitiveString from './SensitiveString.vue'
+
+export default SensitiveString

+ 3 - 0
app/src/components/SetLanguage/index.ts

@@ -0,0 +1,3 @@
+import SetLanguage from './SetLanguage.vue'
+
+export default SetLanguage

+ 1 - 1
app/src/components/SwitchAppearance/SwitchAppearance.vue

@@ -1,6 +1,6 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
 import type { Ref } from 'vue'
 import type { Ref } from 'vue'
-import VPSwitch from '@/components/VPSwitch/VPSwitch.vue'
+import VPSwitch from '@/components/VPSwitch'
 import { useSettingsStore } from '@/pinia'
 import { useSettingsStore } from '@/pinia'
 import VPIconMoon from './icons/VPIconMoon.vue'
 import VPIconMoon from './icons/VPIconMoon.vue'
 import VPIconSun from './icons/VPIconSun.vue'
 import VPIconSun from './icons/VPIconSun.vue'

+ 3 - 0
app/src/components/SwitchAppearance/index.ts

@@ -0,0 +1,3 @@
+import SwitchAppearance from './SwitchAppearance.vue'
+
+export default SwitchAppearance

+ 3 - 0
app/src/components/SystemRestore/index.ts

@@ -0,0 +1,3 @@
+import SystemRestoreContainer from './SystemRestoreContent.vue'
+
+export default SystemRestoreContainer

+ 8 - 0
app/src/components/TwoFA/index.ts

@@ -0,0 +1,8 @@
+import Authorization from './Authorization.vue'
+import use2FAModal from './use2FAModal'
+
+export default Authorization
+
+export {
+  use2FAModal,
+}

+ 3 - 0
app/src/components/VPSwitch/index.ts

@@ -0,0 +1,3 @@
+import VPSwitch from './VPSwitch.vue'
+
+export default VPSwitch

+ 15 - 0
app/src/constants/errors/docker.ts

@@ -0,0 +1,15 @@
+export default {
+  500001: () => $gettext('Docker client not initialized'),
+  500002: () => $gettext('Failed to exec command: {0}'),
+  500003: () => $gettext('Failed to attach to exec instance: {0}'),
+  500004: () => $gettext('Failed to read output: {0}'),
+  500005: () => $gettext('Command exited with unexpected exit code: {0}, error: {1}'),
+  500006: () => $gettext('Container status unknown'),
+  500007: () => $gettext('Failed to inspect container: {0}'),
+  500008: () => $gettext('Nginx is not running in another container'),
+  500009: () => $gettext('Failed to get hostname: {0}'),
+  500010: () => $gettext('Failed to pull image: {0}'),
+  500011: () => $gettext('Failed to inspect current container: {0}'),
+  500012: () => $gettext('Failed to create temp container: {0}'),
+  500013: () => $gettext('Failed to start temp container: {0}'),
+}

+ 1 - 0
app/src/constants/errors/nginx.ts

@@ -1,3 +1,4 @@
 export default {
 export default {
   50001: () => $gettext('Block is nil'),
   50001: () => $gettext('Block is nil'),
+  50002: () => $gettext('Reload nginx failed: {0}'),
 }
 }

+ 87 - 21
app/src/language/ar/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr "أضف مفتاح مرور"
 msgstr "أضف مفتاح مرور"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "إضافة تكوين"
 msgstr "إضافة تكوين"
 
 
@@ -301,7 +301,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -355,7 +355,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "المعلومات الأساسية"
 msgstr "المعلومات الأساسية"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -594,7 +594,7 @@ msgstr[3] "الشهادات المعدلة"
 msgstr[4] "الشهادات المعدلة"
 msgstr[4] "الشهادات المعدلة"
 msgstr[5] "الشهادات المعدلة"
 msgstr[5] "الشهادات المعدلة"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "المسار المتغير"
 msgstr "المسار المتغير"
 
 
@@ -707,6 +707,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "أمر"
 msgstr "أمر"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -787,6 +791,10 @@ msgstr "تم فقدان الاتصال، يرجى تحديث الصفحة."
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1018,7 +1026,7 @@ msgstr "تم الحذف بنجاح"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "نشر"
 msgstr "نشر"
 
 
@@ -1218,6 +1226,10 @@ msgstr "هل تريد إزالة هذا الخادم؟"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "هل تريد إزالة هذا المصدر؟"
 msgstr "هل تريد إزالة هذا المصدر؟"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1281,7 +1293,7 @@ msgstr "تعديل %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "تعديل %{n}"
 msgstr "تعديل %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "تعديل التكوين"
 msgstr "تعديل التكوين"
 
 
@@ -1495,6 +1507,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "فشل في الحصول على الشهادة"
 msgstr "فشل في الحصول على الشهادة"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
@@ -1582,6 +1599,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "فشل في التفعيل %{msg}"
 msgstr "فشل في التفعيل %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1680,6 +1702,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "فشل في التفعيل %{msg}"
 msgstr "فشل في التفعيل %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1699,6 +1726,11 @@ msgstr "فشل في الحصول على معلومات الشهادة"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "فشل في الحصول على معلومات الشهادة"
 msgstr "فشل في الحصول على معلومات الشهادة"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1709,6 +1741,16 @@ msgstr "فشل في الحصول على معلومات الشهادة"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "فشل في الحصول على معلومات الشهادة"
 msgstr "فشل في الحصول على معلومات الشهادة"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1733,6 +1775,11 @@ msgstr "فشل في التفعيل %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 #, fuzzy
 #, fuzzy
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
@@ -1753,6 +1800,11 @@ msgstr "فشل في التفعيل %{msg}"
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr "فشل في التفعيل %{msg}"
 msgstr "فشل في التفعيل %{msg}"
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1777,6 +1829,11 @@ msgstr "فشل في الحصول على الشهادة"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "فشل في الحصول على معلومات الشهادة"
 msgstr "فشل في الحصول على معلومات الشهادة"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1838,14 +1895,10 @@ msgstr "للمستخدمين الصين: /https://mirror.ghproxy.com"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "فشل التكرار"
 msgstr "فشل التكرار"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "تنسيق الكود"
 msgstr "تنسيق الكود"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "خطأ في التنسيق %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "تم التنسيق بنجاح"
 msgstr "تم التنسيق بنجاح"
@@ -1920,7 +1973,7 @@ msgstr "إخفاء"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2101,7 +2154,7 @@ msgid "Invalid file path: {0}"
 msgstr "رمز 2FA أو الاسترداد غير صالح"
 msgstr "رمز 2FA أو الاسترداد غير صالح"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "اسم ملف غير صالح"
 msgstr "اسم ملف غير صالح"
 
 
@@ -2525,7 +2578,7 @@ msgstr "توجيه متعدد الأسطر"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2568,7 +2621,7 @@ msgstr "تثبيت"
 msgid "New name"
 msgid "New name"
 msgstr "اسم جديد"
 msgstr "اسم جديد"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr "مسار جديد"
 msgstr "مسار جديد"
 
 
@@ -2669,6 +2722,11 @@ msgstr "مسار سجل أخطاء Nginx"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx لا يعمل"
 msgstr "Nginx لا يعمل"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx لا يعمل"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 #, fuzzy
 msgid "Nginx is running"
 msgid "Nginx is running"
@@ -2999,11 +3057,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "استخدم رمز الاسترداد"
 msgstr "استخدم رمز الاسترداد"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "الكتابة فوق"
 msgstr "الكتابة فوق"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "الكتابة فوق الملف الموجود"
 msgstr "الكتابة فوق الملف الموجود"
 
 
@@ -3054,7 +3112,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "مسار"
 msgstr "مسار"
@@ -3150,7 +3208,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "يرجى إدخال اسم الملف"
 msgstr "يرجى إدخال اسم الملف"
 
 
@@ -3386,6 +3444,11 @@ msgstr "إعادة تحميل"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "إعادة تحميل nginx"
 msgstr "إعادة تحميل nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3675,7 +3738,7 @@ msgstr "يعمل"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4519,7 +4582,7 @@ msgstr "تم التحديث بنجاح"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4816,6 +4879,9 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "مفاتيح المرور الخاصة بك"
 msgstr "مفاتيح المرور الخاصة بك"
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "خطأ في التنسيق %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "فشل في الحفظ، تم اكتشاف خطأ(أخطاء) في بناء الجملة في التكوين."
 #~ msgstr "فشل في الحفظ، تم اكتشاف خطأ(أخطاء) في بناء الجملة في التكوين."
 
 

+ 88 - 22
app/src/language/de_DE/app.po

@@ -77,7 +77,7 @@ msgid "Add a passkey"
 msgstr "Passkey hinzufügen"
 msgstr "Passkey hinzufügen"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 #, fuzzy
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Konfiguration bearbeiten"
 msgstr "Konfiguration bearbeiten"
@@ -315,7 +315,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -370,7 +370,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Basisinformationen"
 msgstr "Basisinformationen"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
 #, fuzzy
@@ -610,7 +610,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Zertifikat ist gültig"
 msgstr[0] "Zertifikat ist gültig"
 msgstr[1] "Zertifikat ist gültig"
 msgstr[1] "Zertifikat ist gültig"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Zertifikat ist gültig"
 msgstr "Zertifikat ist gültig"
@@ -726,6 +726,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Kommando"
 msgstr "Kommando"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -806,6 +810,10 @@ msgstr "Ver"
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1045,7 +1053,7 @@ msgstr "Erfolgreich deaktiviert"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Ausführen"
 msgstr "Ausführen"
 
 
@@ -1255,6 +1263,10 @@ msgstr "Bist du sicher, dass du diese Richtlinie löschen möchtest?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bist du sicher, dass du diese Richtlinie löschen möchtest?"
 msgstr "Bist du sicher, dass du diese Richtlinie löschen möchtest?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1318,7 +1330,7 @@ msgstr "Bearbeiten %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Bearbeiten %{n}"
 msgstr "Bearbeiten %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Konfiguration bearbeiten"
 msgstr "Konfiguration bearbeiten"
 
 
@@ -1542,6 +1554,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Zertifikat ist gültig"
 msgstr "Zertifikat ist gültig"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1628,6 +1645,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1726,6 +1748,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1745,6 +1772,11 @@ msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1755,6 +1787,16 @@ msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1779,6 +1821,11 @@ msgstr "Aktiviern von %{msg} fehlgeschlagen"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1796,6 +1843,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1819,6 +1871,11 @@ msgstr "Zertifikat ist gültig"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1882,15 +1939,10 @@ msgstr "Für chinesische Benutzer: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Anlegen fehlgeschlagen"
 msgstr "Anlegen fehlgeschlagen"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Formatcode"
 msgstr "Formatcode"
 
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Fehler beim Speichern %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 #, fuzzy
 msgid "Format successfully"
 msgid "Format successfully"
@@ -1968,7 +2020,7 @@ msgstr "Verstecken"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
 msgid "History"
@@ -2150,7 +2202,7 @@ msgid "Invalid file path: {0}"
 msgstr "Ungültige E-Mail!"
 msgstr "Ungültige E-Mail!"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 #, fuzzy
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Ungültige E-Mail!"
 msgstr "Ungültige E-Mail!"
@@ -2595,7 +2647,7 @@ msgstr "Einzelne Anweisung"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2639,7 +2691,7 @@ msgstr "Installieren"
 msgid "New name"
 msgid "New name"
 msgstr "Benutzername"
 msgstr "Benutzername"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "Pfad"
 msgstr "Pfad"
@@ -2743,6 +2795,11 @@ msgstr "Nginx Fehlerlog-Pfad"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx läuft nicht"
 msgstr "Nginx läuft nicht"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx läuft nicht"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 #, fuzzy
 msgid "Nginx is running"
 msgid "Nginx is running"
@@ -3082,11 +3139,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "Benuzte Wiederherstellungscode"
 msgstr "Benuzte Wiederherstellungscode"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Überschreiben"
 msgstr "Überschreiben"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Zu überschreibende Datei existiert"
 msgstr "Zu überschreibende Datei existiert"
 
 
@@ -3137,7 +3194,7 @@ msgstr "Passwort darf nicht länger als 20 Zeichen sein"
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Pfad"
 msgstr "Pfad"
@@ -3237,7 +3294,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 #, fuzzy
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Bitte Benutzernamen eingeben!"
 msgstr "Bitte Benutzernamen eingeben!"
@@ -3488,6 +3545,11 @@ msgstr "Neu laden"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Lade Nginx neu"
 msgstr "Lade Nginx neu"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3792,7 +3854,7 @@ msgstr "Arbeite"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4653,7 +4715,7 @@ msgstr "Speichern erfolgreich"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4961,6 +5023,10 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "Deine Passkeys"
 msgstr "Deine Passkeys"
 
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Fehler beim Speichern %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ msgstr ""
 #~ "Fehler beim Speichern, Syntaxfehler wurden in der Konfiguration erkannt."
 #~ "Fehler beim Speichern, Syntaxfehler wurden in der Konfiguration erkannt."

+ 87 - 22
app/src/language/en/app.po

@@ -78,7 +78,7 @@ msgid "Add a passkey"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 #, fuzzy
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Edit Configuration"
 msgstr "Edit Configuration"
@@ -312,7 +312,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -367,7 +367,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Base information"
 msgstr "Base information"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
 #, fuzzy
@@ -603,7 +603,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Certificate is valid"
 msgstr[0] "Certificate is valid"
 msgstr[1] "Certificate is valid"
 msgstr[1] "Certificate is valid"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
@@ -718,6 +718,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Comments"
 msgstr "Comments"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -798,6 +802,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1034,7 +1042,7 @@ msgstr "Disabled successfully"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
@@ -1243,6 +1251,10 @@ msgstr "Are you sure you want to remove this directive?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Are you sure you want to remove this directive?"
 msgstr "Are you sure you want to remove this directive?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1302,7 +1314,7 @@ msgstr "Edit %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Edit %{n}"
 msgstr "Edit %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Edit Configuration"
 msgstr "Edit Configuration"
 
 
@@ -1525,6 +1537,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
@@ -1612,6 +1629,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Failed to enable %{msg}"
 msgstr "Failed to enable %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1710,6 +1732,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Failed to enable %{msg}"
 msgstr "Failed to enable %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1730,6 +1757,11 @@ msgstr "Certificate is valid"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1740,6 +1772,16 @@ msgstr "Certificate is valid"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Failed to enable %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1764,6 +1806,11 @@ msgstr "Failed to enable %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 #, fuzzy
 #, fuzzy
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
@@ -1784,6 +1831,11 @@ msgstr "Failed to enable %{msg}"
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr "Failed to enable %{msg}"
 msgstr "Failed to enable %{msg}"
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1808,6 +1860,11 @@ msgstr "Certificate is valid"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1869,15 +1926,10 @@ msgstr ""
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Enable failed"
 msgstr "Enable failed"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Save error %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 #, fuzzy
 msgid "Format successfully"
 msgid "Format successfully"
@@ -1954,7 +2006,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2129,7 +2181,7 @@ msgid "Invalid file path: {0}"
 msgstr "Invalid E-mail!"
 msgstr "Invalid E-mail!"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 #, fuzzy
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Invalid E-mail!"
 msgstr "Invalid E-mail!"
@@ -2567,7 +2619,7 @@ msgstr "Single Directive"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2611,7 +2663,7 @@ msgstr "Install"
 msgid "New name"
 msgid "New name"
 msgstr "Username"
 msgstr "Username"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "Path"
 msgstr "Path"
@@ -2714,6 +2766,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -3045,11 +3101,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -3097,7 +3153,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Path"
 msgstr "Path"
@@ -3189,7 +3245,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 #, fuzzy
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Please input your username!"
 msgstr "Please input your username!"
@@ -3431,6 +3487,11 @@ msgstr ""
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3734,7 +3795,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4573,7 +4634,7 @@ msgstr "Saved successfully"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4871,6 +4932,10 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr ""
 msgstr ""
 
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Save error %{msg}"
+
 #, fuzzy
 #, fuzzy
 #~ msgid "Access Token"
 #~ msgid "Access Token"
 #~ msgstr "Sites List"
 #~ msgstr "Sites List"

+ 87 - 21
app/src/language/es/app.po

@@ -83,7 +83,7 @@ msgid "Add a passkey"
 msgstr "Agregar una llave de acceso"
 msgstr "Agregar una llave de acceso"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Agregar configuración"
 msgstr "Agregar configuración"
 
 
@@ -306,7 +306,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -360,7 +360,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Información general"
 msgstr "Información general"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -593,7 +593,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Cambiar Certificado"
 msgstr[0] "Cambiar Certificado"
 msgstr[1] "Cambiar Certificados"
 msgstr[1] "Cambiar Certificados"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Ruta cambiada"
 msgstr "Ruta cambiada"
 
 
@@ -706,6 +706,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Comando"
 msgstr "Comando"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -786,6 +790,10 @@ msgstr "Conexión perdida, por favor actualice la página."
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1019,7 +1027,7 @@ msgstr "Borrado exitoso"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Desplegar"
 msgstr "Desplegar"
 
 
@@ -1219,6 +1227,10 @@ msgstr "¿Quieres eliminar este servidor?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "¿Quieres eliminar esta transmisión?"
 msgstr "¿Quieres eliminar esta transmisión?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1281,7 +1293,7 @@ msgstr "Editar %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Editar %{n}"
 msgstr "Editar %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Editar Configuración"
 msgstr "Editar Configuración"
 
 
@@ -1498,6 +1510,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Falla al obtener el certificado"
 msgstr "Falla al obtener el certificado"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1584,6 +1601,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Error al habilitar %{msg}"
 msgstr "Error al habilitar %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1682,6 +1704,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Error al habilitar %{msg}"
 msgstr "Error al habilitar %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1701,6 +1728,11 @@ msgstr "No se pudo obtener la información del certificado"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "No se pudo obtener la información del certificado"
 msgstr "No se pudo obtener la información del certificado"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1711,6 +1743,16 @@ msgstr "No se pudo obtener la información del certificado"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "No se pudo obtener la información del certificado"
 msgstr "No se pudo obtener la información del certificado"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Error al habilitar %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1735,6 +1777,11 @@ msgstr "Error al habilitar %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1752,6 +1799,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1775,6 +1827,11 @@ msgstr "Falla al obtener el certificado"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "No se pudo obtener la información del certificado"
 msgstr "No se pudo obtener la información del certificado"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1838,14 +1895,10 @@ msgstr "Para usuario chino: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Duplicado fallido"
 msgstr "Duplicado fallido"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Código de formato"
 msgstr "Código de formato"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Error de formato %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "Formateado correctamente"
 msgstr "Formateado correctamente"
@@ -1920,7 +1973,7 @@ msgstr "Ocultar"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2101,7 +2154,7 @@ msgid "Invalid file path: {0}"
 msgstr "Nombre de archivo inválido"
 msgstr "Nombre de archivo inválido"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Nombre de archivo inválido"
 msgstr "Nombre de archivo inválido"
 
 
@@ -2527,7 +2580,7 @@ msgstr "Directiva multilínea"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2570,7 +2623,7 @@ msgstr "Instalar"
 msgid "New name"
 msgid "New name"
 msgstr "Nuevo nombre"
 msgstr "Nuevo nombre"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr "Nueva ruta"
 msgstr "Nueva ruta"
 
 
@@ -2672,6 +2725,11 @@ msgstr "Ruta de registro de errores de Nginx"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx no se está ejecutando"
 msgstr "Nginx no se está ejecutando"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx no se está ejecutando"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 #, fuzzy
 msgid "Nginx is running"
 msgid "Nginx is running"
@@ -3006,11 +3064,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "Usar código de recuperación"
 msgstr "Usar código de recuperación"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Sobrescribir"
 msgstr "Sobrescribir"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Sobrescribir archivo existente"
 msgstr "Sobrescribir archivo existente"
 
 
@@ -3062,7 +3120,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Ruta"
 msgstr "Ruta"
@@ -3163,7 +3221,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Por favor, ingrese un nombre de archivo"
 msgstr "Por favor, ingrese un nombre de archivo"
 
 
@@ -3410,6 +3468,11 @@ msgstr "Recargar"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Recargando Nginx"
 msgstr "Recargando Nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3702,7 +3765,7 @@ msgstr "Corriendo"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4560,7 +4623,7 @@ msgstr "Actualización exitosa"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4862,6 +4925,9 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "Sus llaves de acceso"
 msgstr "Sus llaves de acceso"
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Error de formato %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ msgstr ""
 #~ "No se pudo guardar, se detectó un error(es) de sintaxis en la "
 #~ "No se pudo guardar, se detectó un error(es) de sintaxis en la "

+ 86 - 21
app/src/language/fr_FR/app.po

@@ -82,7 +82,7 @@ msgid "Add a passkey"
 msgstr "Ajouter une clé d'accès"
 msgstr "Ajouter une clé d'accès"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 #, fuzzy
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Modifier la configuration"
 msgstr "Modifier la configuration"
@@ -319,7 +319,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -373,7 +373,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Information générale"
 msgstr "Information générale"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -612,7 +612,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Changer de certificat"
 msgstr[0] "Changer de certificat"
 msgstr[1] "Changer de certificat"
 msgstr[1] "Changer de certificat"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Changer de certificat"
 msgstr "Changer de certificat"
@@ -733,6 +733,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Commentaires"
 msgstr "Commentaires"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -813,6 +817,10 @@ msgstr "Connexion perdue, merci de recharger la page."
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1053,7 +1061,7 @@ msgstr "Désactivé avec succès"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Déployer"
 msgstr "Déployer"
 
 
@@ -1262,6 +1270,10 @@ msgstr "Voulez-vous supprimer ce serveur ?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Voulez-vous supprimer ce serveur ?"
 msgstr "Voulez-vous supprimer ce serveur ?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1327,7 +1339,7 @@ msgstr "Modifier %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Modifier %{n}"
 msgstr "Modifier %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Modifier la configuration"
 msgstr "Modifier la configuration"
 
 
@@ -1552,6 +1564,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Obtenir un certificat"
 msgstr "Obtenir un certificat"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
@@ -1639,6 +1656,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Impossible d'activer %{msg}"
 msgstr "Impossible d'activer %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1737,6 +1759,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Impossible d'activer %{msg}"
 msgstr "Impossible d'activer %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1756,6 +1783,11 @@ msgstr "Échec de l'obtention des informations sur le certificat"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Échec de l'obtention des informations sur le certificat"
 msgstr "Échec de l'obtention des informations sur le certificat"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1766,6 +1798,16 @@ msgstr "Échec de l'obtention des informations sur le certificat"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Échec de l'obtention des informations sur le certificat"
 msgstr "Échec de l'obtention des informations sur le certificat"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Impossible d'activer %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1791,6 +1833,11 @@ msgstr "Impossible d'activer %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr "Erreur lecture nginx.conf"
 msgstr "Erreur lecture nginx.conf"
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 #, fuzzy
 #, fuzzy
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
@@ -1811,6 +1858,11 @@ msgstr "Impossible d'activer %{msg}"
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr "Impossible d'activer %{msg}"
 msgstr "Impossible d'activer %{msg}"
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1836,6 +1888,11 @@ msgstr "Obtenir un certificat"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Échec de l'obtention des informations sur le certificat"
 msgstr "Échec de l'obtention des informations sur le certificat"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1901,14 +1958,10 @@ msgstr "Utilisateur chinois : https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Dupliquer"
 msgstr "Dupliquer"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Code de formatage"
 msgstr "Code de formatage"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Erreur de format %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "Formaté avec succès"
 msgstr "Formaté avec succès"
@@ -1982,7 +2035,7 @@ msgstr "Cacher"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2170,7 +2223,7 @@ msgid "Invalid file path: {0}"
 msgstr "Format de la requête invalide"
 msgstr "Format de la requête invalide"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Nom de fichier invalide"
 msgstr "Nom de fichier invalide"
 
 
@@ -2608,7 +2661,7 @@ msgstr "Directive multiligne"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2652,7 +2705,7 @@ msgstr "Installer"
 msgid "New name"
 msgid "New name"
 msgstr "Nom d'utilisateur"
 msgstr "Nom d'utilisateur"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "Chemin"
 msgstr "Chemin"
@@ -2756,6 +2809,10 @@ msgstr "Chemin du journal des erreurs Nginx"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -3086,11 +3143,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -3138,7 +3195,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Chemin"
 msgstr "Chemin"
@@ -3234,7 +3291,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Veuillez renseigner un nom de fichier"
 msgstr "Veuillez renseigner un nom de fichier"
 
 
@@ -3482,6 +3539,11 @@ msgstr "Recharger"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Rechargement de nginx"
 msgstr "Rechargement de nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3786,7 +3848,7 @@ msgstr "En cours d'éxécution"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4632,7 +4694,7 @@ msgstr "Mis à jour avec succés"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4927,6 +4989,9 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr ""
 msgstr ""
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Erreur de format %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ msgstr ""
 #~ "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été "
 #~ "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été "

+ 87 - 22
app/src/language/ko_KR/app.po

@@ -81,7 +81,7 @@ msgid "Add a passkey"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "구성 추가"
 msgstr "구성 추가"
 
 
@@ -296,7 +296,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "사이트 및 스트림 구성에서 자동으로 색인됩니다."
 msgstr "사이트 및 스트림 구성에서 자동으로 색인됩니다."
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -350,7 +350,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "기본 정보"
 msgstr "기본 정보"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -582,7 +582,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "인증서 변경"
 msgstr[0] "인증서 변경"
 msgstr[1] "인증서 변경"
 msgstr[1] "인증서 변경"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "인증서 변경"
 msgstr "인증서 변경"
@@ -695,6 +695,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "명령어"
 msgstr "명령어"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -775,6 +779,10 @@ msgstr "연결이 끊어졌습니다. 페이지를 새로 고침하세요."
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1009,7 +1017,7 @@ msgstr "성공적으로 삭제됨"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "배포"
 msgstr "배포"
 
 
@@ -1211,6 +1219,10 @@ msgstr "이 서버를 제거하시겠습니까?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "이 업스트림을 제거하시겠습니까?"
 msgstr "이 업스트림을 제거하시겠습니까?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1269,7 +1281,7 @@ msgstr "%{n} 편집"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "%{n} 편집"
 msgstr "%{n} 편집"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "구성 편집"
 msgstr "구성 편집"
 
 
@@ -1491,6 +1503,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "인증서 획득 실패"
 msgstr "인증서 획득 실패"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1577,6 +1594,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "%{msg} 활성화 실패"
 msgstr "%{msg} 활성화 실패"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1675,6 +1697,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "%{msg} 활성화 실패"
 msgstr "%{msg} 활성화 실패"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1694,6 +1721,11 @@ msgstr "인증서 정보 가져오기 실패"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "인증서 정보 가져오기 실패"
 msgstr "인증서 정보 가져오기 실패"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1704,6 +1736,16 @@ msgstr "인증서 정보 가져오기 실패"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "인증서 정보 가져오기 실패"
 msgstr "인증서 정보 가져오기 실패"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "%{msg} 활성화 실패"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1728,6 +1770,11 @@ msgstr "%{msg} 활성화 실패"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1745,6 +1792,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1768,6 +1820,11 @@ msgstr "인증서 획득 실패"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "인증서 정보 가져오기 실패"
 msgstr "인증서 정보 가져오기 실패"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1829,15 +1886,10 @@ msgstr "중국 사용자를 위해: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "복제 실패"
 msgstr "복제 실패"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "코드 형식"
 msgstr "코드 형식"
 
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "형식 오류 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 #, fuzzy
 msgid "Format successfully"
 msgid "Format successfully"
@@ -1913,7 +1965,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2088,7 +2140,7 @@ msgid "Invalid file path: {0}"
 msgstr "Invalid E-mail!"
 msgstr "Invalid E-mail!"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 #, fuzzy
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Invalid E-mail!"
 msgstr "Invalid E-mail!"
@@ -2528,7 +2580,7 @@ msgstr "단일 지시문"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2572,7 +2624,7 @@ msgstr "설치"
 msgid "New name"
 msgid "New name"
 msgstr "이름 변경"
 msgstr "이름 변경"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "경로"
 msgstr "경로"
@@ -2676,6 +2728,10 @@ msgstr "Nginx 오류 로그 경로"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -3008,11 +3064,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "덮어쓰기"
 msgstr "덮어쓰기"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "기존 파일 덮어쓰기"
 msgstr "기존 파일 덮어쓰기"
 
 
@@ -3060,7 +3116,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "경로"
 msgstr "경로"
@@ -3153,7 +3209,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 #, fuzzy
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "사용자 이름을 입력해주세요!"
 msgstr "사용자 이름을 입력해주세요!"
@@ -3402,6 +3458,11 @@ msgstr "리로드"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Nginx 리로딩 중"
 msgstr "Nginx 리로딩 중"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3707,7 +3768,7 @@ msgstr "실행 중"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4544,7 +4605,7 @@ msgstr "성공적으로 저장되었습니다"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4844,6 +4905,10 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr ""
 msgstr ""
 
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "형식 오류 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다."
 #~ msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다."
 
 

+ 73 - 21
app/src/language/messages.pot

@@ -71,7 +71,7 @@ msgstr ""
 
 
 #: src/routes/modules/config.ts:20
 #: src/routes/modules/config.ts:20
 #: src/views/config/ConfigEditor.vue:171
 #: src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr ""
 msgstr ""
 
 
@@ -285,7 +285,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268
+#: src/views/config/ConfigEditor.vue:266
 #: src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195
 #: src/views/config/ConfigList.vue:195
 #: src/views/nginx_log/NginxLog.vue:173
 #: src/views/nginx_log/NginxLog.vue:173
@@ -338,7 +338,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -553,7 +553,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] ""
 msgstr[0] ""
 msgstr[1] ""
 msgstr[1] ""
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr ""
 msgstr ""
 
 
@@ -659,6 +659,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -734,6 +738,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -953,7 +961,7 @@ msgstr ""
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
@@ -1144,6 +1152,10 @@ msgstr ""
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
 msgid "Document"
@@ -1198,7 +1210,7 @@ msgid "Edit %{n}"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/modules/config.ts:30
 #: src/routes/modules/config.ts:30
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr ""
 msgstr ""
 
 
@@ -1403,6 +1415,10 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:4
+msgid "Failed to attach to exec instance: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1479,6 +1495,10 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:13
+msgid "Failed to create temp container: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
 msgstr ""
 msgstr ""
@@ -1563,6 +1583,10 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:3
+msgid "Failed to exec command: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
 msgstr ""
 msgstr ""
@@ -1579,6 +1603,10 @@ msgstr ""
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:10
+msgid "Failed to get hostname: {0}"
+msgstr ""
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
 msgstr ""
 msgstr ""
@@ -1587,6 +1615,14 @@ msgstr ""
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:8
+msgid "Failed to inspect container: {0}"
+msgstr ""
+
+#: src/constants/errors/docker.ts:12
+msgid "Failed to inspect current container: {0}"
+msgstr ""
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgid "Failed to load history records"
 msgstr ""
 msgstr ""
@@ -1607,6 +1643,10 @@ msgstr ""
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+msgid "Failed to pull image: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1623,6 +1663,10 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+msgid "Failed to read output: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
 msgstr ""
 msgstr ""
@@ -1643,6 +1687,10 @@ msgstr ""
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:14
+msgid "Failed to start temp container: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
 msgstr ""
 msgstr ""
@@ -1701,14 +1749,10 @@ msgstr ""
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr ""
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr ""
 msgstr ""
@@ -1779,7 +1823,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
 msgid "History"
@@ -1938,7 +1982,7 @@ msgid "Invalid file path: {0}"
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr ""
 msgstr ""
 
 
@@ -2336,7 +2380,7 @@ msgstr ""
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:7
 #: src/views/config/configColumns.tsx:7
-#: src/views/config/ConfigEditor.vue:311
+#: src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2379,7 +2423,7 @@ msgstr ""
 msgid "New name"
 msgid "New name"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr ""
 msgstr ""
 
 
@@ -2476,6 +2520,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -2785,11 +2833,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -2833,7 +2881,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr ""
 msgstr ""
@@ -2914,7 +2962,7 @@ msgid "Please generate new recovery codes in the preferences immediately to prev
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr ""
 msgstr ""
 
 
@@ -3137,6 +3185,10 @@ msgstr ""
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/nginx.ts:3
+msgid "Reload nginx failed: {0}"
+msgstr ""
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr ""
 msgstr ""
@@ -3400,7 +3452,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4127,7 +4179,7 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/config/configColumns.tsx:36
 #: src/views/config/configColumns.tsx:36
-#: src/views/config/ConfigEditor.vue:331
+#: src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38

+ 87 - 21
app/src/language/ru_RU/app.po

@@ -83,7 +83,7 @@ msgid "Add a passkey"
 msgstr "Добавить ключ доступа"
 msgstr "Добавить ключ доступа"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Добавить конфигурацию"
 msgstr "Добавить конфигурацию"
 
 
@@ -300,7 +300,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -354,7 +354,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Основная информация"
 msgstr "Основная информация"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -581,7 +581,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Сертификат изменен"
 msgstr[0] "Сертификат изменен"
 msgstr[1] "Сертификаты изменены"
 msgstr[1] "Сертификаты изменены"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Путь изменён"
 msgstr "Путь изменён"
 
 
@@ -694,6 +694,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Команда"
 msgstr "Команда"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -774,6 +778,10 @@ msgstr "Соединение потеряно, пожалуйста, обнов
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1004,7 +1012,7 @@ msgstr "Удалено успешно"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Развернуть"
 msgstr "Развернуть"
 
 
@@ -1207,6 +1215,10 @@ msgstr "Хотите удалить этот сервер?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Хотите удалить этот сервер?"
 msgstr "Хотите удалить этот сервер?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1268,7 +1280,7 @@ msgstr "Редактировать %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Редактировать %{n}"
 msgstr "Редактировать %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Редактировать Конфигурацию"
 msgstr "Редактировать Конфигурацию"
 
 
@@ -1482,6 +1494,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Не удалось получить сертификат"
 msgstr "Не удалось получить сертификат"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1568,6 +1585,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Не удалось включить %{msg}"
 msgstr "Не удалось включить %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1666,6 +1688,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Не удалось включить %{msg}"
 msgstr "Не удалось включить %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1685,6 +1712,11 @@ msgstr "Не удалось получить информацию о серти
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Не удалось получить информацию о сертификате"
 msgstr "Не удалось получить информацию о сертификате"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1695,6 +1727,16 @@ msgstr "Не удалось получить информацию о серти
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Не удалось получить информацию о сертификате"
 msgstr "Не удалось получить информацию о сертификате"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Не удалось включить %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1719,6 +1761,11 @@ msgstr "Не удалось включить %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1736,6 +1783,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1759,6 +1811,11 @@ msgstr "Не удалось получить сертификат"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Не удалось получить информацию о сертификате"
 msgstr "Не удалось получить информацию о сертификате"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1822,14 +1879,10 @@ msgstr "Для китайских пользователей: https://mirror.ghp
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Дублирование не удалось"
 msgstr "Дублирование не удалось"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Форматировать код"
 msgstr "Форматировать код"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Ошибка формата %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "Форматирование успешно"
 msgstr "Форматирование успешно"
@@ -1904,7 +1957,7 @@ msgstr "Скрыть"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2085,7 +2138,7 @@ msgid "Invalid file path: {0}"
 msgstr "Неверное имя файла"
 msgstr "Неверное имя файла"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Неверное имя файла"
 msgstr "Неверное имя файла"
 
 
@@ -2508,7 +2561,7 @@ msgstr "Многострочная директива"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2551,7 +2604,7 @@ msgstr "Установить"
 msgid "New name"
 msgid "New name"
 msgstr "Новое имя"
 msgstr "Новое имя"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr "Новый путь"
 msgstr "Новый путь"
 
 
@@ -2653,6 +2706,11 @@ msgstr "Путь для Nginx Error Log"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx не работает"
 msgstr "Nginx не работает"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx не работает"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 #, fuzzy
 msgid "Nginx is running"
 msgid "Nginx is running"
@@ -2983,11 +3041,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "Код OTP или восстановления пуст"
 msgstr "Код OTP или восстановления пуст"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Перезаписать"
 msgstr "Перезаписать"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Перезаписать существующий файл"
 msgstr "Перезаписать существующий файл"
 
 
@@ -3035,7 +3093,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Путь"
 msgstr "Путь"
@@ -3134,7 +3192,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Пожалуйста, введите имя файла"
 msgstr "Пожалуйста, введите имя файла"
 
 
@@ -3380,6 +3438,11 @@ msgstr "Перегрузить"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Перезагружается nginx"
 msgstr "Перезагружается nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3670,7 +3733,7 @@ msgstr "Выполняется"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4517,7 +4580,7 @@ msgstr "Успешно обновлено"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4811,6 +4874,9 @@ msgstr "Ваши старые коды больше не будут работа
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr ""
 msgstr ""
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Ошибка формата %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ msgstr ""
 #~ "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
 #~ "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."

+ 87 - 21
app/src/language/tr_TR/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr "Geçiş anahtarı ekleme"
 msgstr "Geçiş anahtarı ekleme"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Yapılandırma Ekle"
 msgstr "Yapılandırma Ekle"
 
 
@@ -297,7 +297,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -351,7 +351,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Temel bilgiler"
 msgstr "Temel bilgiler"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -582,7 +582,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Değişen Sertifika"
 msgstr[0] "Değişen Sertifika"
 msgstr[1] "Değişen Sertifikalar"
 msgstr[1] "Değişen Sertifikalar"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Değişen Dosya Yolu"
 msgstr "Değişen Dosya Yolu"
 
 
@@ -695,6 +695,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Komut"
 msgstr "Komut"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -775,6 +779,10 @@ msgstr "Bağlantı kesildi, lütfen sayfayı yenileyin."
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1011,7 +1019,7 @@ msgstr "Başarıyla silindi"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Yayınla"
 msgstr "Yayınla"
 
 
@@ -1225,6 +1233,10 @@ msgstr "Bu sunucuyu kaldırmak istiyor musunuz?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bu upstream'i kaldırmak istiyor musunuz?"
 msgstr "Bu upstream'i kaldırmak istiyor musunuz?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1287,7 +1299,7 @@ msgstr "Düzenle %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Düzenle %{n}"
 msgstr "Düzenle %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Yapılandırmayı Düzenle"
 msgstr "Yapılandırmayı Düzenle"
 
 
@@ -1515,6 +1527,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Sertifika alınamadı"
 msgstr "Sertifika alınamadı"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1601,6 +1618,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Etkinleştirilemedi %{msg}"
 msgstr "Etkinleştirilemedi %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1699,6 +1721,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Etkinleştirilemedi %{msg}"
 msgstr "Etkinleştirilemedi %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1718,6 +1745,11 @@ msgstr "Sertifika bilgileri alınamadı"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Sertifika bilgileri alınamadı"
 msgstr "Sertifika bilgileri alınamadı"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1728,6 +1760,16 @@ msgstr "Sertifika bilgileri alınamadı"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Sertifika bilgileri alınamadı"
 msgstr "Sertifika bilgileri alınamadı"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1752,6 +1794,11 @@ msgstr "Etkinleştirilemedi %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1769,6 +1816,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1792,6 +1844,11 @@ msgstr "Sertifika alınamadı"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Sertifika bilgileri alınamadı"
 msgstr "Sertifika bilgileri alınamadı"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1855,14 +1912,10 @@ msgstr "Çinli kullanıcılar için: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Kopyalama başarısız oldu"
 msgstr "Kopyalama başarısız oldu"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Kodu Biçimlendir"
 msgstr "Kodu Biçimlendir"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Biçimlendirme hatası %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "Başarıyla biçimlendirildi"
 msgstr "Başarıyla biçimlendirildi"
@@ -1937,7 +1990,7 @@ msgstr "Gizle"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2119,7 +2172,7 @@ msgid "Invalid file path: {0}"
 msgstr "Geçersiz dosya adı"
 msgstr "Geçersiz dosya adı"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "Geçersiz dosya adı"
 msgstr "Geçersiz dosya adı"
 
 
@@ -2559,7 +2612,7 @@ msgstr "Çok Hatlı Direktif"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2608,7 +2661,7 @@ msgstr "Yükle"
 msgid "New name"
 msgid "New name"
 msgstr "Yeni Ad"
 msgstr "Yeni Ad"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "Yeni Yol"
 msgstr "Yeni Yol"
@@ -2719,6 +2772,11 @@ msgstr "Nginx Hata Günlüğü Yolu"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx çalışmıyor"
 msgstr "Nginx çalışmıyor"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx çalışmıyor"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 #, fuzzy
 msgid "Nginx is running"
 msgid "Nginx is running"
@@ -3074,12 +3132,12 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "Kurtarma kodunu kullanın"
 msgstr "Kurtarma kodunu kullanın"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 #, fuzzy
 #, fuzzy
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Üzerine yaz"
 msgstr "Üzerine yaz"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 #, fuzzy
 #, fuzzy
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Mevcut dosyanın üzerine yaz"
 msgstr "Mevcut dosyanın üzerine yaz"
@@ -3136,7 +3194,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 #, fuzzy
 #, fuzzy
 msgid "Path"
 msgid "Path"
@@ -3245,7 +3303,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 #, fuzzy
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Lütfen bir dosya adı girin"
 msgstr "Lütfen bir dosya adı girin"
@@ -3522,6 +3580,11 @@ msgstr "Tekrar yükle"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Nginx'i yeniden yükleme"
 msgstr "Nginx'i yeniden yükleme"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3843,7 +3906,7 @@ msgstr "Çalışıyor"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4768,7 +4831,7 @@ msgstr "Güncellendi"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -5098,6 +5161,9 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "Geçiş anahtarlarınız"
 msgstr "Geçiş anahtarlarınız"
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Biçimlendirme hatası %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "Kaydedilemedi, yapılandırmada sözdizimi hatası(ları) tespit edildi."
 #~ msgstr "Kaydedilemedi, yapılandırmada sözdizimi hatası(ları) tespit edildi."
 
 

+ 73 - 21
app/src/language/uk_UA/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Додати конфігурацію"
 msgstr "Додати конфігурацію"
 
 
@@ -296,7 +296,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -347,7 +347,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -566,7 +566,7 @@ msgstr[0] ""
 msgstr[1] ""
 msgstr[1] ""
 msgstr[2] ""
 msgstr[2] ""
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr ""
 msgstr ""
 
 
@@ -678,6 +678,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -753,6 +757,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -971,7 +979,7 @@ msgstr ""
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr ""
 msgstr ""
 
 
@@ -1158,6 +1166,10 @@ msgstr ""
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
 msgid "Document"
@@ -1214,7 +1226,7 @@ msgstr ""
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr ""
 msgstr ""
 
 
@@ -1415,6 +1427,10 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:4
+msgid "Failed to attach to exec instance: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1491,6 +1507,10 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:13
+msgid "Failed to create temp container: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
 msgstr ""
 msgstr ""
@@ -1575,6 +1595,10 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:3
+msgid "Failed to exec command: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
 msgstr ""
 msgstr ""
@@ -1591,6 +1615,10 @@ msgstr ""
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:10
+msgid "Failed to get hostname: {0}"
+msgstr ""
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
 msgstr ""
 msgstr ""
@@ -1599,6 +1627,14 @@ msgstr ""
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:8
+msgid "Failed to inspect container: {0}"
+msgstr ""
+
+#: src/constants/errors/docker.ts:12
+msgid "Failed to inspect current container: {0}"
+msgstr ""
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgid "Failed to load history records"
 msgstr ""
 msgstr ""
@@ -1619,6 +1655,10 @@ msgstr ""
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+msgid "Failed to pull image: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1635,6 +1675,10 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+msgid "Failed to read output: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
 msgstr ""
 msgstr ""
@@ -1655,6 +1699,10 @@ msgstr ""
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:14
+msgid "Failed to start temp container: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
 msgstr ""
 msgstr ""
@@ -1714,14 +1762,10 @@ msgstr ""
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr ""
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr ""
 msgstr ""
@@ -1792,7 +1836,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
 msgid "History"
@@ -1959,7 +2003,7 @@ msgid "Invalid file path: {0}"
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr ""
 msgstr ""
 
 
@@ -2358,7 +2402,7 @@ msgstr ""
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2400,7 +2444,7 @@ msgstr ""
 msgid "New name"
 msgid "New name"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr ""
 msgstr ""
 
 
@@ -2496,6 +2540,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -2807,11 +2855,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr ""
 msgstr ""
 
 
@@ -2857,7 +2905,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr ""
 msgstr ""
@@ -2947,7 +2995,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr ""
 msgstr ""
 
 
@@ -3175,6 +3223,10 @@ msgstr ""
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/nginx.ts:3
+msgid "Reload nginx failed: {0}"
+msgstr ""
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr ""
 msgstr ""
@@ -3441,7 +3493,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4216,7 +4268,7 @@ msgstr ""
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38

+ 87 - 22
app/src/language/vi_VN/app.po

@@ -77,7 +77,7 @@ msgid "Add a passkey"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 #, fuzzy
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "Sửa cấu hình"
 msgstr "Sửa cấu hình"
@@ -312,7 +312,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 msgstr ""
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -367,7 +367,7 @@ msgstr ""
 msgid "Base information"
 msgid "Base information"
 msgstr "Thông tin"
 msgstr "Thông tin"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
 #, fuzzy
@@ -606,7 +606,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Thay đổi chứng chỉ"
 msgstr[0] "Thay đổi chứng chỉ"
 msgstr[1] "Thay đổi chứng chỉ"
 msgstr[1] "Thay đổi chứng chỉ"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "Thay đổi chứng chỉ"
 msgstr "Thay đổi chứng chỉ"
@@ -721,6 +721,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "Bình luận"
 msgstr "Bình luận"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -801,6 +805,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1038,7 +1046,7 @@ msgstr "Đã xoá thành công"
 msgid "Demo"
 msgid "Demo"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "Triển khai"
 msgstr "Triển khai"
 
 
@@ -1246,6 +1254,10 @@ msgstr "Bạn muốn xóa máy chủ này ?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bạn muốn xóa máy chủ này ?"
 msgstr "Bạn muốn xóa máy chủ này ?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
 #, fuzzy
@@ -1306,7 +1318,7 @@ msgstr "Sửa %{n}"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Sửa %{n}"
 msgstr "Sửa %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "Sửa cấu hình"
 msgstr "Sửa cấu hình"
 
 
@@ -1531,6 +1543,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "Nhận chứng chỉ"
 msgstr "Nhận chứng chỉ"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
 msgstr ""
@@ -1617,6 +1634,11 @@ msgstr ""
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "Không thể bật %{msg}"
 msgstr "Không thể bật %{msg}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 #, fuzzy
 #, fuzzy
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
@@ -1715,6 +1737,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Không thể bật %{msg}"
 msgstr "Không thể bật %{msg}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 #, fuzzy
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
@@ -1734,6 +1761,11 @@ msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #, fuzzy
 #, fuzzy
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
@@ -1744,6 +1776,16 @@ msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Không thể bật %{msg}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 #, fuzzy
 msgid "Failed to load history records"
 msgid "Failed to load history records"
@@ -1768,6 +1810,11 @@ msgstr "Không thể bật %{msg}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr ""
 msgstr ""
@@ -1785,6 +1832,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 #, fuzzy
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
@@ -1808,6 +1860,11 @@ msgstr "Nhận chứng chỉ"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 #, fuzzy
 #, fuzzy
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
@@ -1870,15 +1927,10 @@ msgstr "Người dùng Trung Quốc: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "Nhân bản thất bại"
 msgstr "Nhân bản thất bại"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "Định dạng code"
 msgstr "Định dạng code"
 
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Lưu lỗi %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 #, fuzzy
 msgid "Format successfully"
 msgid "Format successfully"
@@ -1954,7 +2006,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
 #, fuzzy
@@ -2128,7 +2180,7 @@ msgid "Invalid file path: {0}"
 msgstr "E-mail không chính xác!"
 msgstr "E-mail không chính xác!"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 #, fuzzy
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "E-mail không chính xác!"
 msgstr "E-mail không chính xác!"
@@ -2562,7 +2614,7 @@ msgstr "Single Directive"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2606,7 +2658,7 @@ msgstr "Cài đặt"
 msgid "New name"
 msgid "New name"
 msgstr "Username"
 msgstr "Username"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 #, fuzzy
 msgid "New Path"
 msgid "New Path"
 msgstr "Đường dẫn"
 msgstr "Đường dẫn"
@@ -2709,6 +2761,10 @@ msgstr "Vị trí lưu log lỗi (Error log) của Nginx"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr ""
 msgstr ""
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr ""
 msgstr ""
@@ -3039,11 +3095,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "Ghi đè"
 msgstr "Ghi đè"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "Ghi đè tập tin đã tồn tại"
 msgstr "Ghi đè tập tin đã tồn tại"
 
 
@@ -3091,7 +3147,7 @@ msgstr ""
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "Đường dẫn"
 msgstr "Đường dẫn"
@@ -3185,7 +3241,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 #, fuzzy
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "Vui lòng nhập username!"
 msgstr "Vui lòng nhập username!"
@@ -3431,6 +3487,11 @@ msgstr "Tải lại"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "Tải lại nginx"
 msgstr "Tải lại nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3736,7 +3797,7 @@ msgstr "Running"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4566,7 +4627,7 @@ msgstr "Cập nhật thành công"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4866,6 +4927,10 @@ msgstr ""
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr ""
 msgstr ""
 
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Lưu lỗi %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình."
 #~ msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình."
 
 

+ 87 - 32
app/src/language/zh_CN/app.po

@@ -3,7 +3,7 @@ msgid ""
 msgstr ""
 msgstr ""
 "Project-Id-Version: \n"
 "Project-Id-Version: \n"
 "POT-Creation-Date: \n"
 "POT-Creation-Date: \n"
-"PO-Revision-Date: 2025-04-19 14:14+0800\n"
+"PO-Revision-Date: 2025-04-21 14:19+0800\n"
 "Last-Translator: 0xJacky <me@jackyu.cn>\n"
 "Last-Translator: 0xJacky <me@jackyu.cn>\n"
 "Language-Team: Chinese (Simplified Han script) <https://weblate.nginxui.com/"
 "Language-Team: Chinese (Simplified Han script) <https://weblate.nginxui.com/"
 "projects/nginx-ui/frontend/zh_Hans/>\n"
 "projects/nginx-ui/frontend/zh_Hans/>\n"
@@ -81,7 +81,7 @@ msgid "Add a passkey"
 msgstr "添加 Passkey"
 msgstr "添加 Passkey"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "添加配置"
 msgstr "添加配置"
 
 
@@ -294,7 +294,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "自动索引站点和 Stream 的配置文件。"
 msgstr "自动索引站点和 Stream 的配置文件。"
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -345,7 +345,7 @@ msgstr "Bark"
 msgid "Base information"
 msgid "Base information"
 msgstr "基本信息"
 msgstr "基本信息"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -562,7 +562,7 @@ msgid "Changed Certificate"
 msgid_plural "Changed Certificates"
 msgid_plural "Changed Certificates"
 msgstr[0] "变更证书"
 msgstr[0] "变更证书"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "变更后的路径"
 msgstr "变更后的路径"
 
 
@@ -677,6 +677,10 @@ msgstr "代码补全模型"
 msgid "Command"
 msgid "Command"
 msgstr "命令"
 msgstr "命令"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr "命令以意外退出代码退出:{0},错误:{1}"
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -752,6 +756,10 @@ msgstr "连接中断,请刷新页面。"
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr "连接超时时间"
 msgstr "连接超时时间"
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr "未知容器状态"
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -971,7 +979,7 @@ msgstr "删除成功"
 msgid "Demo"
 msgid "Demo"
 msgstr "Demo"
 msgstr "Demo"
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "部署"
 msgstr "部署"
 
 
@@ -1158,6 +1166,10 @@ msgstr "你想删除这个服务器吗?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "你想删除这个 Upstream 吗?"
 msgstr "你想删除这个 Upstream 吗?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr "Docker 客户端未初始化"
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
 msgid "Document"
@@ -1214,7 +1226,7 @@ msgstr "编辑"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "编辑 %{n}"
 msgstr "编辑 %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "编辑配置"
 msgstr "编辑配置"
 
 
@@ -1415,6 +1427,10 @@ msgstr "外部通知"
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "获取证书失败"
 msgstr "获取证书失败"
 
 
+#: src/constants/errors/docker.ts:4
+msgid "Failed to attach to exec instance: {0}"
+msgstr "连接执行实例失败:{0}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr "备份 Nginx 配置文件失败:{0}"
 msgstr "备份 Nginx 配置文件失败:{0}"
@@ -1491,6 +1507,10 @@ msgstr "创建还原目录失败:{0}"
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "创建符号链接失败:{0}"
 msgstr "创建符号链接失败:{0}"
 
 
+#: src/constants/errors/docker.ts:13
+msgid "Failed to create temp container: {0}"
+msgstr "创建临时容器失败:{0}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
 msgstr "创建临时目录失败"
 msgstr "创建临时目录失败"
@@ -1575,6 +1595,10 @@ msgstr "加密 Nginx UI 目录失败:{0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "符号链接解析失败:{0}"
 msgstr "符号链接解析失败:{0}"
 
 
+#: src/constants/errors/docker.ts:3
+msgid "Failed to exec command: {0}"
+msgstr "执行命令失败:{0}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
 msgstr "解压缩失败:{0}"
 msgstr "解压缩失败:{0}"
@@ -1591,6 +1615,10 @@ msgstr "生成初始化向量失败:{0}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "获取证书信息失败"
 msgstr "获取证书信息失败"
 
 
+#: src/constants/errors/docker.ts:10
+msgid "Failed to get hostname: {0}"
+msgstr "获取主机名失败: {0}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
 msgstr "获取 Nginx 性能参数失败"
 msgstr "获取 Nginx 性能参数失败"
@@ -1599,6 +1627,14 @@ msgstr "获取 Nginx 性能参数失败"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "获取性能数据失败"
 msgstr "获取性能数据失败"
 
 
+#: src/constants/errors/docker.ts:8
+msgid "Failed to inspect container: {0}"
+msgstr "检查容器失败:{0}"
+
+#: src/constants/errors/docker.ts:12
+msgid "Failed to inspect current container: {0}"
+msgstr "检查当前容器失败:{0}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgid "Failed to load history records"
 msgstr "加载历史记录失败"
 msgstr "加载历史记录失败"
@@ -1619,6 +1655,10 @@ msgstr "打开压缩文件失败:{0}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr "解析 nginx.conf 失败"
 msgstr "解析 nginx.conf 失败"
 
 
+#: src/constants/errors/docker.ts:11
+msgid "Failed to pull image: {0}"
+msgstr "拉取镜像失败:{0}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr "读取加密文件失败:{0}"
 msgstr "读取加密文件失败:{0}"
@@ -1635,6 +1675,10 @@ msgstr "读取哈希信息文件失败:{0}"
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr "读取 nginx.conf 失败"
 msgstr "读取 nginx.conf 失败"
 
 
+#: src/constants/errors/docker.ts:5
+msgid "Failed to read output: {0}"
+msgstr "读取输出失败:{0}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
 msgstr "读取符号链接失败:{0}"
 msgstr "读取符号链接失败:{0}"
@@ -1655,6 +1699,10 @@ msgstr "证书撤销失败"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "保存 Nginx 性能参数失败"
 msgstr "保存 Nginx 性能参数失败"
 
 
+#: src/constants/errors/docker.ts:14
+msgid "Failed to start temp container: {0}"
+msgstr "启动临时容器失败:{0}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
 msgstr "验证哈希值失败:{0}"
 msgstr "验证哈希值失败:{0}"
@@ -1714,14 +1762,10 @@ msgstr "中国用户:https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "表单解析失败"
 msgstr "表单解析失败"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "代码格式化"
 msgstr "代码格式化"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "保存错误 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "格式化成功"
 msgstr "格式化成功"
@@ -1792,7 +1836,7 @@ msgstr "隐藏"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr "更高的值意味着更好的连接再利用"
 msgstr "更高的值意味着更好的连接再利用"
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
 msgid "History"
@@ -1962,7 +2006,7 @@ msgid "Invalid file path: {0}"
 msgstr "文件路径无效:{0}"
 msgstr "文件路径无效:{0}"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "文件名无效"
 msgstr "文件名无效"
 
 
@@ -2368,7 +2412,7 @@ msgstr "多行指令"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2410,7 +2454,7 @@ msgstr "新安装"
 msgid "New name"
 msgid "New name"
 msgstr "新名称"
 msgstr "新名称"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr "新路径"
 msgstr "新路径"
 
 
@@ -2506,6 +2550,10 @@ msgstr "Nginx 错误日志路径"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx 未启动"
 msgstr "Nginx 未启动"
 
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr "Nginx 未在另一个容器中运行"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr "Nginx 正在运行"
 msgstr "Nginx 正在运行"
@@ -2817,11 +2865,11 @@ msgstr "其他"
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "OTP 或恢复代码为空"
 msgstr "OTP 或恢复代码为空"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "覆盖"
 msgstr "覆盖"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "覆盖现有文件"
 msgstr "覆盖现有文件"
 
 
@@ -2869,7 +2917,7 @@ msgstr "密码长度不能超过 20 个字符"
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "路径"
 msgstr "路径"
@@ -2961,7 +3009,7 @@ msgid ""
 msgstr "请立即在偏好设置中生成新的恢复码,以防止无法访问您的账户。"
 msgstr "请立即在偏好设置中生成新的恢复码,以防止无法访问您的账户。"
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "请输入文件名"
 msgstr "请输入文件名"
 
 
@@ -3191,6 +3239,10 @@ msgstr "重载"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "重载 Nginx"
 msgstr "重载 Nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+msgid "Reload nginx failed: {0}"
+msgstr "重载 Nginx 失败: {0}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr "在 %{node} 上重载 Nginx 失败,响应:%{resp}"
 msgstr "在 %{node} 上重载 Nginx 失败,响应:%{resp}"
@@ -3459,7 +3511,7 @@ msgstr "运行中"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -3615,19 +3667,19 @@ msgstr "使用 HTTP01 challenge provider"
 
 
 #: src/constants/errors/nginx_log.ts:8
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://"
+"nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath 为空,更多信息请参阅 https://nginxui."
-"com/guide/config-nginx.html"
+"Settings.NginxLogSettings.AccessLogPath 为空,更多信息请参阅 https://"
+"nginxui.com/guide/config-nginx.html"
 
 
 #: src/constants/errors/nginx_log.ts:7
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://"
+"nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath为空,更多信息请参阅 https://nginxui."
-"com/guide/config-nginx.html"
+"Settings.NginxLogSettings.ErrorLogPath为空,更多信息请参阅 https://"
+"nginxui.com/guide/config-nginx.html"
 
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:147
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:147
 msgid "Shared Memory Zone"
 msgid "Shared Memory Zone"
@@ -4252,7 +4304,7 @@ msgstr "更新成功"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4545,6 +4597,9 @@ msgstr "您的旧代码将不再有效。"
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "你的 Passkeys"
 msgstr "你的 Passkeys"
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "保存错误 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "保存失败,在配置中检测到语法错误。"
 #~ msgstr "保存失败,在配置中检测到语法错误。"
 
 
@@ -4641,8 +4696,8 @@ msgstr "你的 Passkeys"
 #~ msgstr "请将远程 Nginx UI 升级到最新版本"
 #~ msgstr "请将远程 Nginx UI 升级到最新版本"
 
 
 #~ msgid ""
 #~ msgid ""
-#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
-#~ "%{resp}"
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %"
+#~ "{resp}"
 #~ msgstr ""
 #~ msgstr ""
 #~ "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,响应:%{resp}"
 #~ "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,响应:%{resp}"
 
 

+ 87 - 21
app/src/language/zh_TW/app.po

@@ -85,7 +85,7 @@ msgid "Add a passkey"
 msgstr "新增通行金鑰"
 msgstr "新增通行金鑰"
 
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgid "Add Configuration"
 msgstr "新增設定"
 msgstr "新增設定"
 
 
@@ -298,7 +298,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "自動從網站和串流設定中索引。"
 msgstr "自動從網站和串流設定中索引。"
 
 
 #: src/views/certificate/components/CertificateEditor.vue:259
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
 #: src/views/stream/components/StreamEditor.vue:106
@@ -349,7 +349,7 @@ msgstr "Bark"
 msgid "Base information"
 msgid "Base information"
 msgstr "基本資訊"
 msgstr "基本資訊"
 
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
 msgid "Basic"
@@ -566,7 +566,7 @@ msgid "Changed Certificate"
 msgid_plural "Changed Certificates"
 msgid_plural "Changed Certificates"
 msgstr[0] "變更後憑證"
 msgstr[0] "變更後憑證"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgid "Changed Path"
 msgstr "變更後路徑"
 msgstr "變更後路徑"
 
 
@@ -685,6 +685,10 @@ msgstr ""
 msgid "Command"
 msgid "Command"
 msgstr "命令"
 msgstr "命令"
 
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -761,6 +765,10 @@ msgstr "連線中斷,請重新整理此頁面。"
 msgid "Connection timeout period"
 msgid "Connection timeout period"
 msgstr "連線逾時時間"
 msgstr "連線逾時時間"
 
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -980,7 +988,7 @@ msgstr "刪除成功"
 msgid "Demo"
 msgid "Demo"
 msgstr "演示"
 msgstr "演示"
 
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgid "Deploy"
 msgstr "部署"
 msgstr "部署"
 
 
@@ -1168,6 +1176,10 @@ msgstr "您要移除此伺服器嗎?"
 msgid "Do you want to remove this upstream?"
 msgid "Do you want to remove this upstream?"
 msgstr "您要移除這個 Upstream 嗎?"
 msgstr "您要移除這個 Upstream 嗎?"
 
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
 msgid "Document"
@@ -1224,7 +1236,7 @@ msgstr "編輯"
 msgid "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "編輯 %{n}"
 msgstr "編輯 %{n}"
 
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgid "Edit Configuration"
 msgstr "編輯設定"
 msgstr "編輯設定"
 
 
@@ -1425,6 +1437,11 @@ msgstr "外部通知"
 msgid "Fail to obtain certificate"
 msgid "Fail to obtain certificate"
 msgstr "取得憑證失敗"
 msgstr "取得憑證失敗"
 
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "無法提取存檔:{0}"
+
 #: src/constants/errors/backup.ts:5
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgid "Failed to backup Nginx config files: {0}"
 msgstr "備份 Nginx 設定檔案失敗:{0}"
 msgstr "備份 Nginx 設定檔案失敗:{0}"
@@ -1501,6 +1518,11 @@ msgstr "無法建立還原目錄:{0}"
 msgid "Failed to create symbolic link: {0}"
 msgid "Failed to create symbolic link: {0}"
 msgstr "建立符號連結失敗:{0}"
 msgstr "建立符號連結失敗:{0}"
 
 
+#: src/constants/errors/docker.ts:13
+#, fuzzy
+msgid "Failed to create temp container: {0}"
+msgstr "無法建立壓縮項目:{0}"
+
 #: src/constants/errors/backup.ts:2
 #: src/constants/errors/backup.ts:2
 msgid "Failed to create temporary directory"
 msgid "Failed to create temporary directory"
 msgstr "無法建立臨時目錄"
 msgstr "無法建立臨時目錄"
@@ -1585,6 +1607,11 @@ msgstr "加密 Nginx UI 目錄失敗:{0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "無法評估符號連結:{0}"
 msgstr "無法評估符號連結:{0}"
 
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/constants/errors/backup.ts:35
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgid "Failed to extract archive: {0}"
 msgstr "無法提取存檔:{0}"
 msgstr "無法提取存檔:{0}"
@@ -1601,6 +1628,11 @@ msgstr "無法生成初始化向量:{0}"
 msgid "Failed to get certificate information"
 msgid "Failed to get certificate information"
 msgstr "取得憑證資訊失敗"
 msgstr "取得憑證資訊失敗"
 
 
+#: src/constants/errors/docker.ts:10
+#, fuzzy
+msgid "Failed to get hostname: {0}"
+msgstr "複製檔案內容失敗:{0}"
+
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 #: src/views/dashboard/components/ParamsOptimization.vue:61
 msgid "Failed to get Nginx performance settings"
 msgid "Failed to get Nginx performance settings"
 msgstr "無法取得 Nginx 效能設定"
 msgstr "無法取得 Nginx 效能設定"
@@ -1609,6 +1641,16 @@ msgstr "無法取得 Nginx 效能設定"
 msgid "Failed to get performance data"
 msgid "Failed to get performance data"
 msgstr "無法取得效能資料"
 msgstr "無法取得效能資料"
 
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "複製檔案內容失敗:{0}"
+
+#: src/constants/errors/docker.ts:12
+#, fuzzy
+msgid "Failed to inspect current container: {0}"
+msgstr "複製檔案內容失敗:{0}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgid "Failed to load history records"
 msgstr "無法載入歷史記錄"
 msgstr "無法載入歷史記錄"
@@ -1629,6 +1671,11 @@ msgstr "無法開啟壓縮檔:{0}"
 msgid "Failed to parse nginx.conf"
 msgid "Failed to parse nginx.conf"
 msgstr "解析 nginx.conf 失敗"
 msgstr "解析 nginx.conf 失敗"
 
 
+#: src/constants/errors/docker.ts:11
+#, fuzzy
+msgid "Failed to pull image: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/constants/errors/backup.ts:53
 #: src/constants/errors/backup.ts:53
 msgid "Failed to read encrypted file: {0}"
 msgid "Failed to read encrypted file: {0}"
 msgstr "無法讀取加密檔案:{0}"
 msgstr "無法讀取加密檔案:{0}"
@@ -1645,6 +1692,11 @@ msgstr "無法讀取雜湊資訊檔案:{0}"
 msgid "Failed to read nginx.conf"
 msgid "Failed to read nginx.conf"
 msgstr "讀取 nginx.conf 失敗"
 msgstr "讀取 nginx.conf 失敗"
 
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/constants/errors/backup.ts:21
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgid "Failed to read symlink: {0}"
 msgstr "讀取符號連結失敗:{0}"
 msgstr "讀取符號連結失敗:{0}"
@@ -1665,6 +1717,11 @@ msgstr "撤銷憑證失敗"
 msgid "Failed to save Nginx performance settings"
 msgid "Failed to save Nginx performance settings"
 msgstr "儲存 Nginx 效能設定失敗"
 msgstr "儲存 Nginx 效能設定失敗"
 
 
+#: src/constants/errors/docker.ts:14
+#, fuzzy
+msgid "Failed to start temp container: {0}"
+msgstr "複製檔案內容失敗:{0}"
+
 #: src/constants/errors/backup.ts:38
 #: src/constants/errors/backup.ts:38
 msgid "Failed to verify hashes: {0}"
 msgid "Failed to verify hashes: {0}"
 msgstr "無法驗證雜湊值:{0}"
 msgstr "無法驗證雜湊值:{0}"
@@ -1724,14 +1781,10 @@ msgstr "中國使用者:https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgid "Form parse failed"
 msgstr "表單解析失敗"
 msgstr "表單解析失敗"
 
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgid "Format Code"
 msgstr "格式化代碼"
 msgstr "格式化代碼"
 
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "格式錯誤 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgid "Format successfully"
 msgstr "成功格式化"
 msgstr "成功格式化"
@@ -1802,7 +1855,7 @@ msgstr "隱藏"
 msgid "Higher value means better connection reuse"
 msgid "Higher value means better connection reuse"
 msgstr ""
 msgstr ""
 
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
 msgid "History"
@@ -1972,7 +2025,7 @@ msgid "Invalid file path: {0}"
 msgstr "無效的檔案路徑:{0}"
 msgstr "無效的檔案路徑:{0}"
 
 
 #: src/views/config/components/Rename.vue:66
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgid "Invalid filename"
 msgstr "無效的檔案名"
 msgstr "無效的檔案名"
 
 
@@ -2379,7 +2432,7 @@ msgstr "多行指令"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2421,7 +2474,7 @@ msgstr "新安裝"
 msgid "New name"
 msgid "New name"
 msgstr "新名稱"
 msgstr "新名稱"
 
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgid "New Path"
 msgstr "新路徑"
 msgstr "新路徑"
 
 
@@ -2519,6 +2572,11 @@ msgstr "Nginx 錯誤日誌路徑"
 msgid "Nginx is not running"
 msgid "Nginx is not running"
 msgstr "Nginx 未執行"
 msgstr "Nginx 未執行"
 
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx 未執行"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgid "Nginx is running"
 msgstr "Nginx 執行中"
 msgstr "Nginx 執行中"
@@ -2832,11 +2890,11 @@ msgstr "其他"
 msgid "Otp or recovery code empty"
 msgid "Otp or recovery code empty"
 msgstr "OTP 或復原碼為空"
 msgstr "OTP 或復原碼為空"
 
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgid "Overwrite"
 msgstr "覆寫"
 msgstr "覆寫"
 
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgid "Overwrite exist file"
 msgstr "覆寫現有檔案"
 msgstr "覆寫現有檔案"
 
 
@@ -2884,7 +2942,7 @@ msgstr "密碼長度不能超過 20 個字元"
 
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgid "Path"
 msgstr "路徑"
 msgstr "路徑"
@@ -2976,7 +3034,7 @@ msgid ""
 msgstr "請立即在偏好設定中產生新的恢復碼,以免無法存取您的賬戶。"
 msgstr "請立即在偏好設定中產生新的恢復碼,以免無法存取您的賬戶。"
 
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgid "Please input a filename"
 msgstr "請輸入檔案名稱"
 msgstr "請輸入檔案名稱"
 
 
@@ -3205,6 +3263,11 @@ msgstr "重新載入"
 msgid "Reload Nginx"
 msgid "Reload Nginx"
 msgstr "重新載入 Nginx"
 msgstr "重新載入 Nginx"
 
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/components/Notification/notifications.ts:10
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr "在節點 %{node} 上重新載入 Nginx 失敗,回應:%{resp}"
 msgstr "在節點 %{node} 上重新載入 Nginx 失敗,回應:%{resp}"
@@ -3473,7 +3536,7 @@ msgstr "執行中"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4266,7 +4329,7 @@ msgstr "更新成功"
 
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4562,6 +4625,9 @@ msgstr "您的舊代碼將不再有效。"
 msgid "Your passkeys"
 msgid "Your passkeys"
 msgstr "您的通行金鑰"
 msgstr "您的通行金鑰"
 
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "格式錯誤 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "儲存失敗,在設定中偵測到語法錯誤。"
 #~ msgstr "儲存失敗,在設定中偵測到語法錯誤。"
 
 

+ 19 - 133
app/src/views/preference/Preference.vue

@@ -1,137 +1,23 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
-import settings from '@/api/settings'
-import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
-import use2FAModal from '@/components/TwoFA/use2FAModal'
-import { useSettingsStore } from '@/pinia'
-import AppSettings from '@/views/preference/AppSettings.vue'
-import AuthSettings from '@/views/preference/AuthSettings.vue'
-import CertSettings from '@/views/preference/CertSettings.vue'
-import ExternalNotify from '@/views/preference/ExternalNotify.vue'
-import HTTPSettings from '@/views/preference/HTTPSettings.vue'
-import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
-import NginxSettings from '@/views/preference/NginxSettings.vue'
-import NodeSettings from '@/views/preference/NodeSettings.vue'
-import OpenAISettings from '@/views/preference/OpenAISettings.vue'
-import ServerSettings from '@/views/preference/ServerSettings.vue'
-import TerminalSettings from '@/views/preference/TerminalSettings.vue'
-import { message } from 'ant-design-vue'
-import { storeToRefs } from 'pinia'
+import FooterToolBar from '@/components/FooterToolbar'
+import {
+  AppSettings,
+  AuthSettings,
+  CertSettings,
+  ExternalNotify,
+  HTTPSettings,
+  LogrotateSettings,
+  NginxSettings,
+  NodeSettings,
+  OpenAISettings,
+  ServerSettings,
+  TerminalSettings,
+} from '@/views/preference/tabs'
+import useSystemSettingsStore from './store'
 
 
-const data = ref<Settings>({
-  app: {
-    page_size: 10,
-    jwt_secret: '',
-  },
-  server: {
-    host: '0.0.0.0',
-    port: 9000,
-    run_mode: 'debug',
-    enable_https: false,
-    ssl_cert: '',
-    ssl_key: '',
-  },
-  database: {
-    name: '',
-  },
-  auth: {
-    ip_white_list: [],
-    ban_threshold_minutes: 10,
-    max_attempts: 10,
-  },
-  casdoor: {
-    endpoint: '',
-    client_id: '',
-    client_secret: '',
-    certificate_path: '',
-    organization: '',
-    application: '',
-    redirect_uri: '',
-  },
-  cert: {
-    email: '',
-    ca_dir: '',
-    renewal_interval: 7,
-    recursive_nameservers: [],
-    http_challenge_port: '9180',
-  },
-  http: {
-    github_proxy: '',
-    insecure_skip_verify: false,
-  },
-  logrotate: {
-    enabled: false,
-    cmd: '',
-    interval: 1440,
-  },
-  nginx: {
-    access_log_path: '',
-    error_log_path: '',
-    config_dir: '',
-    config_path: '',
-    log_dir_white_list: [],
-    pid_path: '',
-    test_config_cmd: '',
-    reload_cmd: '',
-    restart_cmd: '',
-    stub_status_port: 51820,
-  },
-  node: {
-    name: '',
-    secret: '',
-    skip_installation: false,
-    demo: false,
-    icp_number: '',
-    public_security_number: '',
-  },
-  openai: {
-    model: '',
-    base_url: '',
-    proxy: '',
-    token: '',
-    api_type: 'OPEN_AI',
-    enable_code_completion: false,
-    code_completion_model: '',
-  },
-  terminal: {
-    start_cmd: '',
-  },
-  webauthn: {
-    rp_display_name: '',
-    rpid: '',
-    rp_origins: [],
-  },
-})
-
-settings.get().then(r => {
-  data.value = r
-})
-
-const settingsStore = useSettingsStore()
-const { server_name } = storeToRefs(settingsStore)
-const errors = ref<Record<string, Record<string, string>>>({})
-const refAuthSettings = useTemplateRef('refAuthSettings')
-
-async function save() {
-  // fix type
-  data.value.cert.http_challenge_port = data.value.cert.http_challenge_port.toString()
-
-  const otpModal = use2FAModal()
-
-  otpModal.open().then(() => {
-    settings.save(data.value).then(r => {
-      if (!settingsStore.is_remote)
-        server_name.value = r?.server?.name ?? ''
-      data.value = r
-      refAuthSettings.value?.getBannedIPs?.()
-      message.success($gettext('Save successfully'))
-      errors.value = {}
-    })
-  })
-}
+const systemSettingsStore = useSystemSettingsStore()
 
 
-provide('data', data)
-provide('errors', errors)
+systemSettingsStore.getSettings()
 
 
 const router = useRouter()
 const router = useRouter()
 const route = useRoute()
 const route = useRoute()
@@ -195,7 +81,7 @@ onMounted(() => {
           key="auth"
           key="auth"
           :tab="$gettext('Auth')"
           :tab="$gettext('Auth')"
         >
         >
-          <AuthSettings ref="refAuthSettings" />
+          <AuthSettings />
         </ATabPane>
         </ATabPane>
         <ATabPane
         <ATabPane
           key="cert"
           key="cert"
@@ -226,7 +112,7 @@ onMounted(() => {
     <FooterToolBar v-if="activeKey !== 'external_notify'">
     <FooterToolBar v-if="activeKey !== 'external_notify'">
       <AButton
       <AButton
         type="primary"
         type="primary"
-        @click="save"
+        @click="systemSettingsStore.save"
       >
       >
         {{ $gettext('Save') }}
         {{ $gettext('Save') }}
       </AButton>
       </AButton>

+ 0 - 0
app/src/views/preference/components/AddPasskey.vue → app/src/views/preference/components/AuthSettings/AddPasskey.vue


+ 2 - 2
app/src/views/preference/components/Passkey.vue → app/src/views/preference/components/AuthSettings/Passkey.vue

@@ -1,14 +1,14 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import type { Passkey } from '@/api/passkey'
 import type { Passkey } from '@/api/passkey'
 import passkey from '@/api/passkey'
 import passkey from '@/api/passkey'
-import ReactiveFromNow from '@/components/ReactiveFromNow/ReactiveFromNow.vue'
+import ReactiveFromNow from '@/components/ReactiveFromNow'
 import { formatDateTime } from '@/lib/helper'
 import { formatDateTime } from '@/lib/helper'
 import { useUserStore } from '@/pinia'
 import { useUserStore } from '@/pinia'
-import AddPasskey from '@/views/preference/components/AddPasskey.vue'
 import { DeleteOutlined, EditOutlined, KeyOutlined } from '@ant-design/icons-vue'
 import { DeleteOutlined, EditOutlined, KeyOutlined } from '@ant-design/icons-vue'
 import { message } from 'ant-design-vue'
 import { message } from 'ant-design-vue'
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
 import relativeTime from 'dayjs/plugin/relativeTime'
 import relativeTime from 'dayjs/plugin/relativeTime'
+import AddPasskey from './AddPasskey.vue'
 
 
 dayjs.extend(relativeTime)
 dayjs.extend(relativeTime)
 
 

+ 1 - 1
app/src/views/preference/components/RecoveryCodes.vue → app/src/views/preference/components/AuthSettings/RecoveryCodes.vue

@@ -2,7 +2,7 @@
 import type { TwoFAStatus } from '@/api/2fa'
 import type { TwoFAStatus } from '@/api/2fa'
 import type { RecoveryCode } from '@/api/recovery'
 import type { RecoveryCode } from '@/api/recovery'
 import recovery from '@/api/recovery'
 import recovery from '@/api/recovery'
-import use2FAModal from '@/components/TwoFA/use2FAModal'
+import { use2FAModal } from '@/components/TwoFA'
 import { CopyOutlined, WarningOutlined } from '@ant-design/icons-vue'
 import { CopyOutlined, WarningOutlined } from '@ant-design/icons-vue'
 import { UseClipboard } from '@vueuse/components'
 import { UseClipboard } from '@vueuse/components'
 import { message } from 'ant-design-vue'
 import { message } from 'ant-design-vue'

+ 2 - 2
app/src/views/preference/components/TOTP.vue → app/src/views/preference/components/AuthSettings/TOTP.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import type { RecoveryCode } from '@/api/recovery'
 import type { RecoveryCode } from '@/api/recovery'
 import otp from '@/api/otp'
 import otp from '@/api/otp'
-import OTPInput from '@/components/OTPInput/OTPInput.vue'
-import use2FAModal from '@/components/TwoFA/use2FAModal'
+import OTPInput from '@/components/OTPInput'
+import { use2FAModal } from '@/components/TwoFA'
 import { CheckCircleOutlined } from '@ant-design/icons-vue'
 import { CheckCircleOutlined } from '@ant-design/icons-vue'
 import { UseClipboard } from '@vueuse/components'
 import { UseClipboard } from '@vueuse/components'
 import { message } from 'ant-design-vue'
 import { message } from 'ant-design-vue'

+ 11 - 0
app/src/views/preference/components/AuthSettings/index.ts

@@ -0,0 +1,11 @@
+import AddPasskey from './AddPasskey.vue'
+import Passkey from './Passkey.vue'
+import RecoveryCodes from './RecoveryCodes.vue'
+import TOTP from './TOTP.vue'
+
+export {
+  AddPasskey,
+  Passkey,
+  RecoveryCodes,
+  TOTP,
+}

+ 127 - 0
app/src/views/preference/store/index.ts

@@ -0,0 +1,127 @@
+import type { Settings } from '@/api/settings'
+import settings from '@/api/settings'
+import { use2FAModal } from '@/components/TwoFA'
+import { useSettingsStore } from '@/pinia'
+import { message } from 'ant-design-vue'
+import { defineStore } from 'pinia'
+
+const useSystemSettingsStore = defineStore('systemSettings', () => {
+  const data = ref<Settings>({
+    app: {
+      page_size: 10,
+      jwt_secret: '',
+    },
+    server: {
+      host: '0.0.0.0',
+      port: 9000,
+      run_mode: 'debug',
+      enable_https: false,
+      ssl_cert: '',
+      ssl_key: '',
+    },
+    database: {
+      name: '',
+    },
+    auth: {
+      ip_white_list: [],
+      ban_threshold_minutes: 10,
+      max_attempts: 10,
+    },
+    casdoor: {
+      endpoint: '',
+      client_id: '',
+      client_secret: '',
+      certificate_path: '',
+      organization: '',
+      application: '',
+      redirect_uri: '',
+    },
+    cert: {
+      email: '',
+      ca_dir: '',
+      renewal_interval: 7,
+      recursive_nameservers: [],
+      http_challenge_port: '9180',
+    },
+    http: {
+      github_proxy: '',
+      insecure_skip_verify: false,
+    },
+    logrotate: {
+      enabled: false,
+      cmd: '',
+      interval: 1440,
+    },
+    nginx: {
+      access_log_path: '',
+      error_log_path: '',
+      config_dir: '',
+      config_path: '',
+      log_dir_white_list: [],
+      pid_path: '',
+      test_config_cmd: '',
+      reload_cmd: '',
+      restart_cmd: '',
+      stub_status_port: 51820,
+      container_name: '',
+    },
+    node: {
+      name: '',
+      secret: '',
+      skip_installation: false,
+      demo: false,
+      icp_number: '',
+      public_security_number: '',
+    },
+    openai: {
+      model: '',
+      base_url: '',
+      proxy: '',
+      token: '',
+      api_type: 'OPEN_AI',
+      enable_code_completion: false,
+      code_completion_model: '',
+    },
+    terminal: {
+      start_cmd: '',
+    },
+    webauthn: {
+      rp_display_name: '',
+      rpid: '',
+      rp_origins: [],
+    },
+  })
+  const errors = ref<Record<string, Record<string, string>>>({})
+
+  function getSettings() {
+    settings.get().then(r => {
+      data.value = r
+    })
+  }
+
+  async function save() {
+    if (!data.value)
+      return
+
+    // fix type
+    data.value.cert.http_challenge_port = data.value.cert.http_challenge_port.toString()
+
+    const otpModal = use2FAModal()
+
+    otpModal.open().then(() => {
+      settings.save(data.value!).then(r => {
+        const settingsStore = useSettingsStore()
+        const { server_name } = storeToRefs(settingsStore)
+        if (!settingsStore.is_remote)
+          server_name.value = r?.server?.name ?? ''
+        data.value = r
+        message.success($gettext('Save successfully'))
+        errors.value = {}
+      })
+    })
+  }
+
+  return { data, errors, getSettings, save }
+})
+
+export default useSystemSettingsStore

+ 4 - 3
app/src/views/preference/AppSettings.vue → app/src/views/preference/tabs/AppSettings.vue

@@ -1,8 +1,9 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
-import SensitiveString from '@/components/SensitiveString/SensitiveString.vue'
+import SensitiveString from '@/components/SensitiveString'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 6 - 6
app/src/views/preference/AuthSettings.vue → app/src/views/preference/tabs/AuthSettings.vue

@@ -1,18 +1,18 @@
 <script setup lang="tsx">
 <script setup lang="tsx">
 import type { TwoFAStatus } from '@/api/2fa'
 import type { TwoFAStatus } from '@/api/2fa'
 import type { RecoveryCode } from '@/api/recovery'
 import type { RecoveryCode } from '@/api/recovery'
-import type { BannedIP, Settings } from '@/api/settings'
+import type { BannedIP } from '@/api/settings'
 import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import type { Ref } from 'vue'
 import type { Ref } from 'vue'
 import twoFA from '@/api/2fa'
 import twoFA from '@/api/2fa'
 import setting from '@/api/settings'
 import setting from '@/api/settings'
-import RecoveryCodes from '@/views/preference/components/RecoveryCodes.vue'
-import TOTP from '@/views/preference/components/TOTP.vue'
 import { message } from 'ant-design-vue'
 import { message } from 'ant-design-vue'
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
-import PasskeyRegistration from './components/Passkey.vue'
+import { Passkey, RecoveryCodes, TOTP } from '../components/AuthSettings'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 
 
 const bannedIPColumns = [{
 const bannedIPColumns = [{
   title: $gettext('IP'),
   title: $gettext('IP'),
@@ -68,7 +68,7 @@ get2FAStatus()
   <div class="flex justify-center">
   <div class="flex justify-center">
     <div>
     <div>
       <h2>{{ $gettext('2FA Settings') }}</h2>
       <h2>{{ $gettext('2FA Settings') }}</h2>
-      <PasskeyRegistration class="mb-4" />
+      <Passkey class="mb-4" />
 
 
       <TOTP
       <TOTP
         v-model:recovery-codes="recoveryCodes"
         v-model:recovery-codes="recoveryCodes"

+ 3 - 3
app/src/views/preference/CertSettings.vue → app/src/views/preference/tabs/CertSettings.vue

@@ -1,10 +1,10 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
 import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
 import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
 import Draggable from 'vuedraggable'
 import Draggable from 'vuedraggable'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
-const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>
+const systemSettingsStore = useSystemSettingsStore()
+const { data, errors } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 2 - 2
app/src/views/preference/ExternalNotify.vue → app/src/views/preference/tabs/ExternalNotify.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import externalNotify from '@/api/external_notify'
 import externalNotify from '@/api/external_notify'
 import { StdCurd } from '@/components/StdDesign/StdDataDisplay'
 import { StdCurd } from '@/components/StdDesign/StdDataDisplay'
-import columns from './components/ExternalNotify/columns'
-import ExternalNotifyEditor from './components/ExternalNotify/ExternalNotifyEditor.vue'
+import ExternalNotifyEditor from '../components/ExternalNotify'
+import columns from '../components/ExternalNotify/columns'
 </script>
 </script>
 
 
 <template>
 <template>

+ 3 - 3
app/src/views/preference/HTTPSettings.vue → app/src/views/preference/tabs/HTTPSettings.vue

@@ -1,8 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
-const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>
+const systemSettingsStore = useSystemSettingsStore()
+const { data, errors } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 3 - 2
app/src/views/preference/LogrotateSettings.vue → app/src/views/preference/tabs/LogrotateSettings.vue

@@ -1,7 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 16 - 2
app/src/views/preference/NginxSettings.vue → app/src/views/preference/tabs/NginxSettings.vue

@@ -1,7 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>
@@ -42,6 +43,19 @@ const data: Ref<Settings> = inject('data') as Ref<Settings>
     <AFormItem :label="$gettext('Nginx Restart Command')">
     <AFormItem :label="$gettext('Nginx Restart Command')">
       {{ data.nginx.restart_cmd }}
       {{ data.nginx.restart_cmd }}
     </AFormItem>
     </AFormItem>
+    <AFormItem :label="$gettext('Nginx Control Mode')">
+      <div v-if="data.nginx.container_name">
+        <ATag color="blue" tag>
+          {{ $gettext('External Docker Container') }}
+        </ATag>
+        {{ data.nginx.container_name }}
+      </div>
+      <div v-else>
+        <ATag color="green" tag>
+          {{ $gettext('Local') }}
+        </ATag>
+      </div>
+    </AFormItem>
   </AForm>
   </AForm>
 </template>
 </template>
 
 

+ 4 - 4
app/src/views/preference/NodeSettings.vue → app/src/views/preference/tabs/NodeSettings.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
-import SensitiveString from '@/components/SensitiveString/SensitiveString.vue'
+import SensitiveString from '@/components/SensitiveString'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
-const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>
+const systemSettingsStore = useSystemSettingsStore()
+const { data, errors } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 3 - 3
app/src/views/preference/OpenAISettings.vue → app/src/views/preference/tabs/OpenAISettings.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
 import { LLM_MODELS, LLM_PROVIDERS } from '@/constants/llm'
 import { LLM_MODELS, LLM_PROVIDERS } from '@/constants/llm'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
-const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>
+const systemSettingsStore = useSystemSettingsStore()
+const { data, errors } = storeToRefs(systemSettingsStore)
 
 
 const models = LLM_MODELS.map(model => ({
 const models = LLM_MODELS.map(model => ({
   value: model,
   value: model,

+ 3 - 2
app/src/views/preference/ServerSettings.vue → app/src/views/preference/tabs/ServerSettings.vue

@@ -1,9 +1,10 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import type { Cert } from '@/api/cert'
 import type { Cert } from '@/api/cert'
-import type { Settings } from '@/api/settings'
 import ChangeCert from '@/views/site/site_edit/components/Cert/ChangeCert.vue'
 import ChangeCert from '@/views/site/site_edit/components/Cert/ChangeCert.vue'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 
 
 function handleCertChange(certs: Cert[]) {
 function handleCertChange(certs: Cert[]) {
   if (certs.length > 0 && data.value?.server) {
   if (certs.length > 0 && data.value?.server) {

+ 3 - 2
app/src/views/preference/TerminalSettings.vue → app/src/views/preference/tabs/TerminalSettings.vue

@@ -1,7 +1,8 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import type { Settings } from '@/api/settings'
+import useSystemSettingsStore from '../store'
 
 
-const data: Ref<Settings> = inject('data') as Ref<Settings>
+const systemSettingsStore = useSystemSettingsStore()
+const { data } = storeToRefs(systemSettingsStore)
 </script>
 </script>
 
 
 <template>
 <template>

+ 11 - 0
app/src/views/preference/tabs/index.ts

@@ -0,0 +1,11 @@
+export { default as AppSettings } from './AppSettings.vue'
+export { default as AuthSettings } from './AuthSettings.vue'
+export { default as CertSettings } from './CertSettings.vue'
+export { default as ExternalNotify } from './ExternalNotify.vue'
+export { default as HTTPSettings } from './HTTPSettings.vue'
+export { default as LogrotateSettings } from './LogrotateSettings.vue'
+export { default as NginxSettings } from './NginxSettings.vue'
+export { default as NodeSettings } from './NodeSettings.vue'
+export { default as OpenAISettings } from './OpenAISettings.vue'
+export { default as ServerSettings } from './ServerSettings.vue'
+export { default as TerminalSettings } from './TerminalSettings.vue'

+ 20 - 6
docs/guide/config-nginx.md

@@ -101,18 +101,12 @@ If the `--sbin-path` path cannot be obtained from `nginx -V`, Nginx UI will use
 nginx
 nginx
 ```
 ```
 
 
-
-
 If the `--sbin-path` path can be obtained, Nginx UI will use the following command to start the Nginx service:
 If the `--sbin-path` path can be obtained, Nginx UI will use the following command to start the Nginx service:
 
 
 ```bash
 ```bash
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 ```
 ```
 
 
-## Stub Status
-
-In this section, we will introduce configuration options in Nginx UI for the Nginx stub status module.
-
 ### StubStatusPort
 ### StubStatusPort
 - Type: `uint`
 - Type: `uint`
 - Default: `51820`
 - Default: `51820`
@@ -123,3 +117,23 @@ This option is used to set the port for the Nginx stub status module. The stub s
 ::: tip Tip
 ::: tip Tip
 Make sure the port you set is not being used by other services.
 Make sure the port you set is not being used by other services.
 :::
 :::
+
+## Container Control
+
+In this section, we will introduce configuration options in Nginx UI for controlling Nginx services running in another Docker container.
+
+### ContainerName
+- Type: `string`
+- Version: `>= v2.0.0-rc.6`
+
+This option is used to specify the name of the Docker container where Nginx is running.
+
+If this option is empty, Nginx UI will control the Nginx service on the local machine or within the current container.
+
+If this option is not empty, Nginx UI will control the Nginx service running in the specified container.
+
+::: tip Tip
+If you are using the official Nginx UI container and want to control Nginx in another container, you must map the host's docker.sock to the Nginx UI container.
+
+For example: `-v /var/run/docker.sock:/var/run/docker.sock`
+:::

+ 18 - 4
docs/zh_CN/guide/config-nginx.md

@@ -108,10 +108,6 @@ nginx
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 ```
 ```
 
 
-## Stub Status
-
-在本节中,我们将会介绍 Nginx UI 中关于 Nginx stub status 模块的配置选项。
-
 ### StubStatusPort
 ### StubStatusPort
 - 类型:`uint`
 - 类型:`uint`
 - 默认值:`51820`
 - 默认值:`51820`
@@ -123,4 +119,22 @@ start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 请确保您设置的端口未被其他服务占用。
 请确保您设置的端口未被其他服务占用。
 :::
 :::
 
 
+## 容器控制
+
+在本节中,我们将会介绍 Nginx UI 中关于控制运行在另一个 Docker 容器中的 Nginx 服务的配置选项。
+
+### ContainerName
+- 类型:`string`
+- 版本:`>= v2.0.0-rc.6`
+
+此选项用于指定运行 Nginx 的 Docker 容器名称。
+
+如果此选项为空,Nginx UI 将控制本机或当前容器内的 Nginx 服务。
+
+如果此选项不为空,Nginx UI 将控制运行在指定容器中的 Nginx 服务。
 
 
+::: tip 提示
+如果使用 Nginx UI 官方容器,想要控制另外一个容器里的 Nginx,务必将宿主机内的 docker.sock 映射到 Nginx UI 官方容器中。
+
+例如:`-v /var/run/docker.sock:/var/run/docker.sock`
+:::

+ 20 - 4
docs/zh_TW/guide/config-nginx.md

@@ -101,10 +101,6 @@ start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PID
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 ```
 ```
 
 
-## Stub Status
-
-在本節中,我們將會介紹 Nginx UI 中關於 Nginx stub status 模組的設定選項。
-
 ### StubStatusPort
 ### StubStatusPort
 - 類型:`uint`
 - 類型:`uint`
 - 預設值:`51820`
 - 預設值:`51820`
@@ -115,3 +111,23 @@ start-stop-daemon --start --quiet --pidfile $PID --exec $SBIN_PATH
 ::: tip 提示
 ::: tip 提示
 請確保您設定的連接埠未被其他服務佔用。
 請確保您設定的連接埠未被其他服務佔用。
 :::
 :::
+
+## 容器控制
+
+在本節中,我們將會介紹 Nginx UI 中關於控制運行在另一個 Docker 容器中的 Nginx 服務的設定選項。
+
+### ContainerName
+- 類型:`string`
+- 版本:`>= v2.0.0-rc.6`
+
+此選項用於指定執行 Nginx 的 Docker 容器名稱。
+
+如果此選項為空,Nginx UI 將控制本機或當前容器內的 Nginx 服務。
+
+如果此選項不為空,Nginx UI 將控制執行在指定容器中的 Nginx 服務。
+
+::: tip 提示
+如果使用 Nginx UI 官方容器,想要控制另外一個容器裡的 Nginx,務必將宿主機內的 docker.sock 映射到 Nginx UI 官方容器中。
+
+例如:`-v /var/run/docker.sock:/var/run/docker.sock`
+:::

+ 13 - 0
go.mod

@@ -9,6 +9,7 @@ require (
 	github.com/casdoor/casdoor-go-sdk v1.5.0
 	github.com/casdoor/casdoor-go-sdk v1.5.0
 	github.com/creack/pty v1.1.24
 	github.com/creack/pty v1.1.24
 	github.com/dgraph-io/ristretto/v2 v2.2.0
 	github.com/dgraph-io/ristretto/v2 v2.2.0
+	github.com/docker/docker v28.1.1+incompatible
 	github.com/dustin/go-humanize v1.0.1
 	github.com/dustin/go-humanize v1.0.1
 	github.com/elliotchance/orderedmap/v3 v3.1.0
 	github.com/elliotchance/orderedmap/v3 v3.1.0
 	github.com/fsnotify/fsnotify v1.9.0
 	github.com/fsnotify/fsnotify v1.9.0
@@ -75,6 +76,7 @@ require (
 	github.com/Azure/go-autorest/logger v0.2.2 // indirect
 	github.com/Azure/go-autorest/logger v0.2.2 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.1 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.1 // indirect
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
+	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
 	github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
@@ -106,10 +108,14 @@ require (
 	github.com/civo/civogo v0.3.98 // indirect
 	github.com/civo/civogo v0.3.98 // indirect
 	github.com/cloudflare/cloudflare-go v0.115.0 // indirect
 	github.com/cloudflare/cloudflare-go v0.115.0 // indirect
 	github.com/cloudwego/base64x v0.1.5 // indirect
 	github.com/cloudwego/base64x v0.1.5 // indirect
+	github.com/containerd/log v0.1.0 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
+	github.com/distribution/reference v0.6.0 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
+	github.com/docker/go-connections v0.5.0 // indirect
+	github.com/docker/go-units v0.5.0 // indirect
 	github.com/ebitengine/purego v0.8.2 // indirect
 	github.com/ebitengine/purego v0.8.2 // indirect
 	github.com/exoscale/egoscale/v3 v3.1.14 // indirect
 	github.com/exoscale/egoscale/v3 v3.1.14 // indirect
 	github.com/fatih/color v1.18.0 // indirect
 	github.com/fatih/color v1.18.0 // indirect
@@ -184,8 +190,12 @@ require (
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/moby/docker-image-spec v1.3.1 // indirect
+	github.com/moby/sys/atomicwriter v0.1.0 // indirect
+	github.com/moby/term v0.5.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
 	github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
 	github.com/nrdcg/auroradns v1.1.0 // indirect
 	github.com/nrdcg/auroradns v1.1.0 // indirect
 	github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea // indirect
 	github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea // indirect
@@ -199,6 +209,8 @@ require (
 	github.com/nrdcg/nodion v0.1.0 // indirect
 	github.com/nrdcg/nodion v0.1.0 // indirect
 	github.com/nrdcg/porkbun v0.4.0 // indirect
 	github.com/nrdcg/porkbun v0.4.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
+	github.com/opencontainers/go-digest v1.0.0 // indirect
+	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/oracle/oci-go-sdk/v65 v65.89.1 // indirect
 	github.com/oracle/oci-go-sdk/v65 v65.89.1 // indirect
 	github.com/ovh/go-ovh v1.7.0 // indirect
 	github.com/ovh/go-ovh v1.7.0 // indirect
@@ -257,6 +269,7 @@ require (
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
 	go.opentelemetry.io/otel v1.35.0 // indirect
 	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect
 	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect

+ 37 - 9
go.sum

@@ -632,6 +632,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
 github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
 github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
@@ -675,6 +677,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
 github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
 github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -698,8 +702,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.105 h1:Bj8SsBTGElGniuL83+VqfHnxZIPc7n+rzpwDZIB4rZg=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.105/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
@@ -790,7 +792,6 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -825,6 +826,8 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -853,8 +856,16 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY=
 github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY=
 github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8=
 github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8=
+github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
+github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -912,8 +923,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
 github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
 github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
 github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
-github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
-github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
 github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
 github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
 github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
 github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -1168,9 +1177,12 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
 github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
 github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
 github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
 github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
@@ -1478,6 +1490,14 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
 github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
+github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -1486,6 +1506,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=
 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=
@@ -1549,6 +1571,10 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h
 github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
 github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
 github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
 github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
@@ -1770,8 +1796,6 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW
 github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
 github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
 github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
 github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145 h1:DETyir/MtG+GLOD0OatzjrQTTXRguFSJo1ZtPXtbIQw=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk=
@@ -1817,8 +1841,6 @@ github.com/urfave/cli/v3 v3.1.1 h1:bNnl8pFI5dxPOjeONvFCDFoECLQsceDG4ejahs4Jtxk=
 github.com/urfave/cli/v3 v3.1.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
 github.com/urfave/cli/v3 v3.1.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
-github.com/volcengine/volc-sdk-golang v1.0.203 h1:y4zZEjKp6nz3UK8Tb/qdz9tvB915KLO6nc1WNME0Zb8=
-github.com/volcengine/volc-sdk-golang v1.0.203/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/volcengine/volc-sdk-golang v1.0.204 h1:Njid6coReHV2gWc3bsqWMQf+K8jveauzW8zEX08CTzI=
 github.com/volcengine/volc-sdk-golang v1.0.204 h1:Njid6coReHV2gWc3bsqWMQf+K8jveauzW8zEX08CTzI=
 github.com/volcengine/volc-sdk-golang v1.0.204/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/volcengine/volc-sdk-golang v1.0.204/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/vultr/govultr/v3 v3.19.1 h1:31rOP5Tz40AOc8h6Ws4ryzqAniUBffgRhy9uMG/EFvs=
 github.com/vultr/govultr/v3 v3.19.1 h1:31rOP5Tz40AOc8h6Ws4ryzqAniUBffgRhy9uMG/EFvs=
@@ -1881,6 +1903,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRND
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
 go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
 go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
 go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
 go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
 go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
 go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
 go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
 go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
 go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
 go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
@@ -1892,6 +1918,8 @@ go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
+go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=

+ 3 - 2
internal/cmd/main.go

@@ -26,10 +26,11 @@ func NewAppCmd() *cli.Command {
 				},
 				},
 			},
 			},
 			{
 			{
-				Name:  "reset-password",
-				Usage: "Reset the initial user password",
+				Name:   "reset-password",
+				Usage:  "Reset the initial user password",
 				Action: user.ResetInitUserPassword,
 				Action: user.ResetInitUserPassword,
 			},
 			},
+			UpgradeDockerStep2Command,
 		},
 		},
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			&cli.StringFlag{
 			&cli.StringFlag{

+ 23 - 0
internal/cmd/upgrade_docker.go

@@ -0,0 +1,23 @@
+package cmd
+
+import (
+	"context"
+
+	"github.com/0xJacky/Nginx-UI/internal/docker"
+	"github.com/uozi-tech/cosy/logger"
+	"github.com/urfave/cli/v3"
+)
+
+// Command to be executed in the temporary container
+var UpgradeDockerStep2Command = &cli.Command{
+	Name:   "upgrade-docker-step2",
+	Usage:  "Execute the second step of Docker container upgrade (to be run inside the temp container)",
+	Action: UpgradeDockerStep2,
+}
+
+// UpgradeDockerStep2 executes the second step in the temporary container
+func UpgradeDockerStep2(ctx context.Context, command *cli.Command) error {
+	logger.Info("Starting Docker OTA upgrade step 2 from CLI...")
+
+	return docker.UpgradeStepTwo(ctx)
+}

+ 5 - 1
internal/config/save.go

@@ -45,7 +45,11 @@ func Save(absPath string, content string, cfg *model.Config) (err error) {
 		return
 		return
 	}
 	}
 
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	} 
+
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 22 - 0
internal/docker/docker.go

@@ -0,0 +1,22 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/docker/docker/client"
+)
+
+// Initialize Docker client from environment variables
+func initClient() (cli *client.Client, err error) {
+	cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
+	if err != nil {
+		return
+	}
+	// Optionally ping the server to ensure the connection is valid
+	_, err = cli.Ping(context.Background())
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 20 - 0
internal/docker/errors.go

@@ -0,0 +1,20 @@
+package docker
+
+import "github.com/uozi-tech/cosy"
+
+var (
+	e                                    = cosy.NewErrorScope("docker")
+	ErrClientNotInitialized              = e.New(500001, "docker client not initialized")
+	ErrFailedToExec                      = e.New(500002, "failed to exec command: {0}")
+	ErrFailedToAttach                    = e.New(500003, "failed to attach to exec instance: {0}")
+	ErrReadOutput                        = e.New(500004, "failed to read output: {0}")
+	ErrExitUnexpected                    = e.New(500005, "command exited with unexpected exit code: {0}, error: {1}")
+	ErrContainerStatusUnknown            = e.New(500006, "container status unknown")
+	ErrInspectContainer                  = e.New(500007, "failed to inspect container: {0}")
+	ErrNginxNotRunningInAnotherContainer = e.New(500008, "nginx is not running in another container")
+	ErrFailedToGetHostname               = e.New(500009, "failed to get hostname: {0}")
+	ErrFailedToPullImage                 = e.New(500010, "failed to pull image: {0}")
+	ErrFailedToInspectCurrentContainer   = e.New(500011, "failed to inspect current container: {0}")
+	ErrFailedToCreateTempContainer       = e.New(500012, "failed to create temp container: {0}")
+	ErrFailedToStartTempContainer        = e.New(500013, "failed to start temp container: {0}")
+)

+ 80 - 0
internal/docker/exec.go

@@ -0,0 +1,80 @@
+package docker
+
+import (
+	"bytes"
+	"context"
+	"io"
+	"strconv"
+
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/uozi-tech/cosy"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+// Exec executes a command in a specific container and returns the output.
+func Exec(ctx context.Context, command []string) (string, error) {
+	if !settings.NginxSettings.RunningInAnotherContainer() {
+		return "", ErrNginxNotRunningInAnotherContainer
+	}
+
+	cli, err := initClient()
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	execConfig := container.ExecOptions{
+		AttachStdout: true,
+		AttachStderr: true, // Also attach stderr to capture errors from the command
+		Cmd:          command,
+	}
+
+	// Create the exec instance
+	execCreateResp, err := cli.ContainerExecCreate(ctx, settings.NginxSettings.ContainerName, execConfig)
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrFailedToExec, err.Error())
+	}
+	execID := execCreateResp.ID
+
+	// Attach to the exec instance
+	hijackedResp, err := cli.ContainerExecAttach(ctx, execID, container.ExecAttachOptions{})
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrFailedToAttach, err.Error())
+	}
+	defer hijackedResp.Close()
+
+	// Read the output
+	var outBuf, errBuf bytes.Buffer
+	outputDone := make(chan error)
+
+	go func() {
+		// stdcopy.StdCopy demultiplexes the stream into two buffers
+		_, err = stdcopy.StdCopy(&outBuf, &errBuf, hijackedResp.Reader)
+		outputDone <- err
+	}()
+
+	select {
+	case err := <-outputDone:
+		if err != nil && err != io.EOF { // io.EOF is expected when the stream finishes
+			return "", cosy.WrapErrorWithParams(ErrReadOutput, err.Error())
+		}
+	case <-ctx.Done():
+		return "", cosy.WrapErrorWithParams(ErrReadOutput, ctx.Err().Error())
+	}
+
+	// Optionally inspect the exec process to check the exit code
+	execInspectResp, err := cli.ContainerExecInspect(ctx, execID)
+	logger.Debug("docker exec result", outBuf.String(), errBuf.String())
+
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrExitUnexpected, err.Error())
+	} else if execInspectResp.ExitCode != 0 {
+		// Command exited with a non-zero status code. Return stderr as part of the error.
+		return outBuf.String(), cosy.WrapErrorWithParams(ErrExitUnexpected, strconv.Itoa(execInspectResp.ExitCode), errBuf.String())
+	}
+
+	// Return stdout if successful
+	return outBuf.String(), nil
+}

+ 329 - 0
internal/docker/ota.go

@@ -0,0 +1,329 @@
+package docker
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/0xJacky/Nginx-UI/internal/upgrader"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/image"
+	"github.com/docker/docker/client"
+	"github.com/pkg/errors"
+	"github.com/uozi-tech/cosy"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+const (
+	ImageName  = "uozi/nginx-ui"
+	TempPrefix = "nginx-ui-temp-"
+	OldSuffix  = "_old"
+)
+
+// getTimestampedTempName returns a temporary container name with timestamp
+func getTimestampedTempName() string {
+	return fmt.Sprintf("%s%d", TempPrefix, time.Now().Unix())
+}
+
+// removeAllTempContainers removes all containers with the TempPrefix
+func removeAllTempContainers(ctx context.Context, cli *client.Client) (err error) {
+	containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
+	if err != nil {
+		return
+	}
+
+	for _, c := range containers {
+		for _, name := range c.Names {
+			processedName := strings.TrimPrefix(name, "/")
+			if strings.HasPrefix(processedName, TempPrefix) {
+				err = cli.ContainerRemove(ctx, c.ID, container.RemoveOptions{Force: true})
+				if err != nil {
+					logger.Error("Failed to remove temp container:", err)
+				} else {
+					logger.Info("Successfully removed temp container:", processedName)
+				}
+				break
+			}
+		}
+	}
+
+	return nil
+}
+
+// UpgradeStepOne Trigger in the OTA upgrade
+func UpgradeStepOne(channel string) (err error) {
+	ctx := context.Background()
+
+	// 1. Get the tag of the latest release
+	release, err := upgrader.GetRelease(channel)
+	if err != nil {
+		return err
+	}
+	tag := release.TagName
+
+	// 2. Pull the image
+	cli, err := initClient()
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	// Pull the image with the specified tag
+	out, err := cli.ImagePull(ctx, fmt.Sprintf("%s:%s", ImageName, tag), image.PullOptions{})
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrFailedToPullImage, err.Error())
+	}
+	defer out.Close()
+
+	// Wait for pull to complete by reading the output
+	io.Copy(os.Stdout, out)
+
+	// 3. Create a temp container
+	// Clean up any existing temp containers
+	err = removeAllTempContainers(ctx, cli)
+	if err != nil {
+		logger.Error("Failed to clean up existing temp containers:", err)
+		// Continue execution despite cleanup errors
+	}
+
+	// Generate timestamped temp container name
+	tempContainerName := getTimestampedTempName()
+
+	// Get current container name
+	hostname, err := os.Hostname()
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrFailedToGetHostname, err.Error())
+	}
+	containerInfo, err := cli.ContainerInspect(ctx, hostname)
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrFailedToInspectCurrentContainer, err.Error())
+	}
+	currentContainerName := strings.TrimPrefix(containerInfo.Name, "/")
+
+	// Set up the command for the temp container to execute step 2
+	upgradeCmd := []string{"./nginx-ui", "upgrade-docker-step2"}
+
+	// Add old container name as environment variable
+	containerEnv := containerInfo.Config.Env
+	containerEnv = append(containerEnv, fmt.Sprintf("NGINX_UI_CONTAINER_NAME=%s", currentContainerName))
+
+	// Create temp container using new image
+	_, err = cli.ContainerCreate(
+		ctx,
+		&container.Config{
+			Image: fmt.Sprintf("%s:%s", ImageName, tag),
+			Cmd:   upgradeCmd, // Use upgrade command instead of original command
+			Env:   containerEnv,
+		},
+		&container.HostConfig{
+			Binds:         containerInfo.HostConfig.Binds,
+			PortBindings:  containerInfo.HostConfig.PortBindings,
+			RestartPolicy: containerInfo.HostConfig.RestartPolicy,
+		},
+		nil,
+		nil,
+		tempContainerName,
+	)
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrFailedToCreateTempContainer, err.Error())
+	}
+
+	// Start the temp container to execute step 2
+	err = cli.ContainerStart(ctx, tempContainerName, container.StartOptions{})
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrFailedToStartTempContainer, err.Error())
+	}
+
+	// Output status information
+	logger.Info("Docker OTA upgrade step 1 completed. Temp container started to execute step 2.")
+
+	return nil
+}
+
+// UpgradeStepTwo Trigger in the temp container
+func UpgradeStepTwo(ctx context.Context) (err error) {
+	// 1. Copy the old config
+	cli, err := initClient()
+	if err != nil {
+		return
+	}
+	defer cli.Close()
+
+	// Get old container name from environment variable, fallback to settings if not available
+	currentContainerName := os.Getenv("NGINX_UI_CONTAINER_NAME")
+	if currentContainerName == "" {
+		return errors.New("could not find old container name")
+	}
+	// Get the current running temp container name
+	// Since we can't directly get our own container name from inside, we'll search all temp containers
+	containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
+	if err != nil {
+		return errors.Wrap(err, "failed to list containers")
+	}
+
+	// Find containers with the temp prefix
+	var tempContainerName string
+	for _, c := range containers {
+		for _, name := range c.Names {
+			processedName := strings.TrimPrefix(name, "/")
+			if strings.HasPrefix(processedName, TempPrefix) {
+				tempContainerName = processedName
+				break
+			}
+		}
+		if tempContainerName != "" {
+			break
+		}
+	}
+
+	if tempContainerName == "" {
+		return errors.New("could not find temp container")
+	}
+
+	// Get temp container info to get the new image
+	tempContainerInfo, err := cli.ContainerInspect(ctx, tempContainerName)
+	if err != nil {
+		return errors.Wrap(err, "failed to inspect temp container")
+	}
+	newImage := tempContainerInfo.Config.Image
+
+	// Get current container info
+	oldContainerInfo, err := cli.ContainerInspect(ctx, currentContainerName)
+	if err != nil {
+		return errors.Wrap(err, "failed to inspect current container")
+	}
+
+	// 2. Stop the old container and rename to _old
+	err = cli.ContainerStop(ctx, currentContainerName, container.StopOptions{})
+	if err != nil {
+		return errors.Wrap(err, "failed to stop current container")
+	}
+
+	// Rename the old container with _old suffix
+	err = cli.ContainerRename(ctx, currentContainerName, currentContainerName+OldSuffix)
+	if err != nil {
+		return errors.Wrap(err, "failed to rename old container")
+	}
+
+	// 3. Use the old config to create and start a new container with the updated image
+	// Create new container with original config but using the new image
+	newContainerEnv := oldContainerInfo.Config.Env
+	// Pass the old container name to the new container
+	newContainerEnv = append(newContainerEnv, fmt.Sprintf("NGINX_UI_CONTAINER_NAME=%s", currentContainerName))
+
+	_, err = cli.ContainerCreate(
+		ctx,
+		&container.Config{
+			Image:        newImage,
+			Cmd:          oldContainerInfo.Config.Cmd,
+			Env:          newContainerEnv,
+			Entrypoint:   oldContainerInfo.Config.Entrypoint,
+			Labels:       oldContainerInfo.Config.Labels,
+			ExposedPorts: oldContainerInfo.Config.ExposedPorts,
+			Volumes:      oldContainerInfo.Config.Volumes,
+			WorkingDir:   oldContainerInfo.Config.WorkingDir,
+		},
+		&container.HostConfig{
+			Binds:         oldContainerInfo.HostConfig.Binds,
+			PortBindings:  oldContainerInfo.HostConfig.PortBindings,
+			RestartPolicy: oldContainerInfo.HostConfig.RestartPolicy,
+			NetworkMode:   oldContainerInfo.HostConfig.NetworkMode,
+			Mounts:        oldContainerInfo.HostConfig.Mounts,
+			Privileged:    oldContainerInfo.HostConfig.Privileged,
+		},
+		nil,
+		nil,
+		currentContainerName,
+	)
+	if err != nil {
+		// If creation fails, try to recover
+		recoverErr := cli.ContainerRename(ctx, currentContainerName+OldSuffix, currentContainerName)
+		if recoverErr == nil {
+			// Start old container
+			recoverErr = cli.ContainerStart(ctx, currentContainerName, container.StartOptions{})
+			if recoverErr == nil {
+				return errors.Wrap(err, "failed to create new container, recovered to old container")
+			}
+		}
+		return errors.Wrap(err, "failed to create new container and failed to recover")
+	}
+
+	// Start the new container
+	err = cli.ContainerStart(ctx, currentContainerName, container.StartOptions{})
+	if err != nil {
+		// If startup fails, try to recover
+		// First remove the failed new container
+		removeErr := cli.ContainerRemove(ctx, currentContainerName, container.RemoveOptions{Force: true})
+		if removeErr != nil {
+			logger.Error("Failed to remove failed new container:", removeErr)
+		}
+
+		// Rename the old container back to original
+		recoverErr := cli.ContainerRename(ctx, currentContainerName+OldSuffix, currentContainerName)
+		if recoverErr == nil {
+			// Start old container
+			recoverErr = cli.ContainerStart(ctx, currentContainerName, container.StartOptions{})
+			if recoverErr == nil {
+				return errors.Wrap(err, "failed to start new container, recovered to old container")
+			}
+		}
+		return errors.Wrap(err, "failed to start new container and failed to recover")
+	}
+
+	logger.Info("Docker OTA upgrade step 2 completed successfully. New container is running.")
+	return nil
+}
+
+// UpgradeStepThree Trigger in the new container
+func UpgradeStepThree() error {
+	ctx := context.Background()
+	// Remove the old container
+	cli, err := initClient()
+	if err != nil {
+		return cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	// Get old container name from environment variable, fallback to settings if not available
+	currentContainerName := os.Getenv("NGINX_UI_CONTAINER_NAME")
+	if currentContainerName == "" {
+		logger.Warn("Old container name not found in environment, skipping cleanup")
+		return nil
+	}
+	oldContainerName := currentContainerName + OldSuffix
+
+	// Check if old container exists and remove it if it does
+	containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
+	if err != nil {
+		return errors.Wrap(err, "failed to list containers")
+	}
+
+	for _, c := range containers {
+		for _, name := range c.Names {
+			processedName := strings.TrimPrefix(name, "/")
+			// Remove old container
+			if processedName == oldContainerName {
+				err = cli.ContainerRemove(ctx, c.ID, container.RemoveOptions{Force: true})
+				if err != nil {
+					logger.Error("Failed to remove old container:", err)
+					// Continue execution, don't interrupt because of failure to remove old container
+				} else {
+					logger.Info("Successfully removed old container:", oldContainerName)
+				}
+				break
+			}
+		}
+	}
+
+	// Clean up all temp containers
+	err = removeAllTempContainers(ctx, cli)
+	if err != nil {
+		logger.Error("Failed to clean up temp containers:", err)
+		// Continue execution despite cleanup errors
+	}
+
+	return nil
+}

+ 29 - 0
internal/docker/stat_path.go

@@ -0,0 +1,29 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+// StatPath checks if a path exists in the container
+func StatPath(path string) bool {
+	if !settings.NginxSettings.RunningInAnotherContainer() {
+		return false
+	}
+
+	cli, err := initClient()
+	if err != nil {
+		return false
+	}
+	defer cli.Close()
+
+	_, err = cli.ContainerStatPath(context.Background(), settings.NginxSettings.ContainerName, path)
+	if err != nil {
+		logger.Error("Failed to stat path", "error", err)
+		return false
+	}
+
+	return true
+}

+ 58 - 0
internal/docker/status.go

@@ -0,0 +1,58 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/docker/docker/client"
+	"github.com/uozi-tech/cosy"
+)
+
+type ContainerStatus int
+
+const (
+	ContainerStatusCreated ContainerStatus = iota
+	ContainerStatusRunning
+	ContainerStatusPaused
+	ContainerStatusRestarting
+	ContainerStatusRemoving
+	ContainerStatusExited
+	ContainerStatusDead
+	ContainerStatusUnknown
+	ContainerStatusNotFound
+)
+
+var (
+	containerStatusMap = map[string]ContainerStatus{
+		"created":    ContainerStatusCreated,
+		"running":    ContainerStatusRunning,
+		"paused":     ContainerStatusPaused,
+		"restarting": ContainerStatusRestarting,
+		"removing":   ContainerStatusRemoving,
+		"exited":     ContainerStatusExited,
+		"dead":       ContainerStatusDead,
+	}
+)
+
+// GetContainerStatus checks the status of a given container.
+func GetContainerStatus(ctx context.Context, containerID string) (ContainerStatus, error) {
+	cli, err := initClient()
+	if err != nil {
+		return ContainerStatusUnknown, cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	containerJSON, err := cli.ContainerInspect(ctx, containerID)
+	if err != nil {
+		if client.IsErrNotFound(err) {
+			return ContainerStatusNotFound, nil // Container doesn't exist
+		}
+		return ContainerStatusUnknown, cosy.WrapErrorWithParams(ErrInspectContainer, err.Error())
+	}
+
+	// Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead"
+	status, ok := containerStatusMap[containerJSON.State.Status]
+	if !ok {
+		return ContainerStatusUnknown, ErrContainerStatusUnknown
+	}
+	return status, nil
+}

+ 13 - 0
internal/kernel/boot.go

@@ -12,6 +12,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/cert"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
 	"github.com/0xJacky/Nginx-UI/internal/cluster"
 	"github.com/0xJacky/Nginx-UI/internal/cluster"
 	"github.com/0xJacky/Nginx-UI/internal/cron"
 	"github.com/0xJacky/Nginx-UI/internal/cron"
+	"github.com/0xJacky/Nginx-UI/internal/docker"
 	"github.com/0xJacky/Nginx-UI/internal/passkey"
 	"github.com/0xJacky/Nginx-UI/internal/passkey"
 	"github.com/0xJacky/Nginx-UI/internal/validation"
 	"github.com/0xJacky/Nginx-UI/internal/validation"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/model"
@@ -35,6 +36,7 @@ func Boot() {
 		InitCryptoSecret,
 		InitCryptoSecret,
 		validation.Init,
 		validation.Init,
 		cache.Init,
 		cache.Init,
+		CheckAndCleanupOTAContainers,
 	}
 	}
 
 
 	syncs := []func(){
 	syncs := []func(){
@@ -129,3 +131,14 @@ func InitJsExtensionType() {
 	// See https://github.com/golang/go/issues/32350
 	// See https://github.com/golang/go/issues/32350
 	_ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
 	_ = mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
 }
 }
+
+// CheckAndCleanupOTAContainers Check and cleanup OTA update temporary containers
+func CheckAndCleanupOTAContainers() {
+	// Execute the third step cleanup operation at startup
+	err := docker.UpgradeStepThree()
+	if err != nil {
+		logger.Error("Failed to cleanup OTA containers:", err)
+	} else {
+		logger.Info("OTA container cleanup completed successfully")
+	}
+}

+ 1 - 0
internal/nginx/errors.go

@@ -5,4 +5,5 @@ import "github.com/uozi-tech/cosy"
 var (
 var (
 	e             = cosy.NewErrorScope("nginx")
 	e             = cosy.NewErrorScope("nginx")
 	ErrBlockIsNil = e.New(50001, "block is nil")
 	ErrBlockIsNil = e.New(50001, "block is nil")
+	ErrReloadFailed = e.New(50002, "reload nginx failed: {0}")
 )
 )

+ 28 - 0
internal/nginx/exec.go

@@ -0,0 +1,28 @@
+package nginx
+
+import (
+	"context"
+	"os/exec"
+
+	"github.com/0xJacky/Nginx-UI/internal/docker"
+	"github.com/0xJacky/Nginx-UI/settings"
+)
+
+func execShell(cmd string) (stdOut string, stdErr error) {
+	return execCommand("/bin/sh", "-c", cmd)
+}
+
+func execCommand(name string, cmd ...string) (stdOut string, stdErr error) {
+	switch settings.NginxSettings.RunningInAnotherContainer() {
+	case true:
+		cmd = append([]string{name}, cmd...)
+		stdOut, stdErr = docker.Exec(context.Background(), cmd)
+	case false:
+		bytes, err := exec.Command(name, cmd...).CombinedOutput()
+		stdOut = string(bytes)
+		if err != nil {
+			stdErr = err
+		}
+	}
+	return
+}

+ 38 - 51
internal/nginx/nginx.go

@@ -2,46 +2,41 @@ package nginx
 
 
 import (
 import (
 	"os"
 	"os"
-	"os/exec"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
+	"github.com/0xJacky/Nginx-UI/internal/docker"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/0xJacky/Nginx-UI/settings"
 )
 )
 
 
 var (
 var (
 	mutex      sync.Mutex
 	mutex      sync.Mutex
-	lastOutput string
+	lastStdOut string
+	lastStdErr error
 )
 )
 
 
-func TestConf() (out string) {
+// TestConfig tests the nginx config
+func TestConfig() (stdOut string, stdErr error) {
 	mutex.Lock()
 	mutex.Lock()
 	defer mutex.Unlock()
 	defer mutex.Unlock()
 	if settings.NginxSettings.TestConfigCmd != "" {
 	if settings.NginxSettings.TestConfigCmd != "" {
-		out = execShell(settings.NginxSettings.TestConfigCmd)
-
-		return
+		return execShell(settings.NginxSettings.TestConfigCmd)
 	}
 	}
-
-	out = execCommand("nginx", "-t")
-
-	return
+	return execCommand("nginx", "-t")
 }
 }
 
 
-func Reload() (out string) {
+// Reload reloads the nginx
+func Reload() (stdOut string, stdErr error) {
 	mutex.Lock()
 	mutex.Lock()
 	defer mutex.Unlock()
 	defer mutex.Unlock()
 	if settings.NginxSettings.ReloadCmd != "" {
 	if settings.NginxSettings.ReloadCmd != "" {
-		out = execShell(settings.NginxSettings.ReloadCmd)
-		return
+		return execShell(settings.NginxSettings.ReloadCmd)
 	}
 	}
-
-	out = execCommand("nginx", "-s", "reload")
-
-	return
+	return execCommand("nginx", "-s", "reload")
 }
 }
 
 
+// Restart restarts the nginx
 func Restart() {
 func Restart() {
 	mutex.Lock()
 	mutex.Lock()
 	defer mutex.Unlock()
 	defer mutex.Unlock()
@@ -50,41 +45,45 @@ func Restart() {
 	time.Sleep(500 * time.Millisecond)
 	time.Sleep(500 * time.Millisecond)
 
 
 	if settings.NginxSettings.RestartCmd != "" {
 	if settings.NginxSettings.RestartCmd != "" {
-		lastOutput = execShell(settings.NginxSettings.RestartCmd)
-
+		lastStdOut, lastStdErr = execShell(settings.NginxSettings.RestartCmd)
 		return
 		return
 	}
 	}
 
 
 	pidPath := GetPIDPath()
 	pidPath := GetPIDPath()
 	daemon := GetSbinPath()
 	daemon := GetSbinPath()
 
 
-	lastOutput = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+	if lastStdErr != nil {
+		return
+	}
 
 
 	if daemon == "" {
 	if daemon == "" {
-		lastOutput += execCommand("nginx")
-
+		lastStdOut, lastStdErr = execCommand("nginx")
 		return
 		return
 	}
 	}
 
 
-	lastOutput += execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
-
+	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
 	return
 	return
 }
 }
 
 
-func GetLastOutput() string {
+// GetLastOutput returns the last output of the nginx command
+func GetLastOutput() (stdOut string, stdErr error) {
 	mutex.Lock()
 	mutex.Lock()
 	defer mutex.Unlock()
 	defer mutex.Unlock()
-	return lastOutput
+	return lastStdOut, lastStdErr
 }
 }
 
 
 // GetModulesPath returns the nginx modules path
 // GetModulesPath returns the nginx modules path
 func GetModulesPath() string {
 func GetModulesPath() string {
 	// First try to get from nginx -V output
 	// First try to get from nginx -V output
-	output := execCommand("nginx", "-V")
-	if output != "" {
+	stdOut, stdErr := execCommand("nginx", "-V")
+	if stdErr != nil {
+		return ""
+	}
+	if stdOut != "" {
 		// Look for --modules-path in the output
 		// Look for --modules-path in the output
-		if strings.Contains(output, "--modules-path=") {
-			parts := strings.Split(output, "--modules-path=")
+		if strings.Contains(stdOut, "--modules-path=") {
+			parts := strings.Split(stdOut, "--modules-path=")
 			if len(parts) > 1 {
 			if len(parts) > 1 {
 				// Extract the path
 				// Extract the path
 				path := strings.Split(parts[1], " ")[0]
 				path := strings.Split(parts[1], " ")[0]
@@ -99,28 +98,16 @@ func GetModulesPath() string {
 	return "/usr/lib/nginx/modules"
 	return "/usr/lib/nginx/modules"
 }
 }
 
 
-func execShell(cmd string) (out string) {
-	bytes, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
-	out = string(bytes)
-	if err != nil {
-		out += " " + err.Error()
-	}
-	return
-}
-
-func execCommand(name string, cmd ...string) (out string) {
-	bytes, err := exec.Command(name, cmd...).CombinedOutput()
-	out = string(bytes)
-	if err != nil {
-		out += " " + err.Error()
-	}
-	return
-}
-
 func IsNginxRunning() bool {
 func IsNginxRunning() bool {
 	pidPath := GetPIDPath()
 	pidPath := GetPIDPath()
-	if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
-		return false
+	switch settings.NginxSettings.RunningInAnotherContainer() {
+	case true:
+		return docker.StatPath(pidPath)
+	case false:
+		if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
+			return false
+		}
+		return true
 	}
 	}
-	return true
+	return false
 }
 }

+ 4 - 1
internal/site/disable.go

@@ -35,7 +35,10 @@ func Disable(name string) (err error) {
 		return
 		return
 	}
 	}
 
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 8 - 2
internal/site/enable.go

@@ -35,13 +35,19 @@ func Enable(name string) (err error) {
 	}
 	}
 
 
 	// Test nginx config, if not pass, then disable the site.
 	// Test nginx config, if not pass, then disable the site.
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		_ = os.Remove(enabledConfigFilePath)
 		_ = os.Remove(enabledConfigFilePath)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 	}
 
 
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 16 - 4
internal/site/maintenance.go

@@ -76,7 +76,10 @@ func EnableMaintenance(name string) (err error) {
 	}
 	}
 
 
 	// Test nginx config, if not pass, then restore original configuration
 	// Test nginx config, if not pass, then restore original configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		// Configuration error, cleanup and revert
 		// Configuration error, cleanup and revert
 		_ = os.Remove(maintenanceConfigPath)
 		_ = os.Remove(maintenanceConfigPath)
@@ -87,7 +90,10 @@ func EnableMaintenance(name string) (err error) {
 	}
 	}
 
 
 	// Reload nginx
 	// Reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}
@@ -132,7 +138,10 @@ func DisableMaintenance(name string) (err error) {
 	}
 	}
 
 
 	// Test nginx config, if not pass, then revert
 	// Test nginx config, if not pass, then revert
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		// Configuration error, cleanup and revert
 		// Configuration error, cleanup and revert
 		_ = os.Remove(enabledConfigFilePath)
 		_ = os.Remove(enabledConfigFilePath)
@@ -141,7 +150,10 @@ func DisableMaintenance(name string) (err error) {
 	}
 	}
 
 
 	// Reload nginx
 	// Reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 		return fmt.Errorf("%s", output)
 	}
 	}

+ 13 - 6
internal/site/rename.go

@@ -2,16 +2,17 @@ package site
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"net/http"
+	"os"
+	"runtime"
+	"sync"
+
 	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/go-resty/resty/v2"
 	"github.com/go-resty/resty/v2"
 	"github.com/uozi-tech/cosy/logger"
 	"github.com/uozi-tech/cosy/logger"
-	"net/http"
-	"os"
-	"runtime"
-	"sync"
 )
 )
 
 
 func Rename(oldName string, newName string) (err error) {
 func Rename(oldName string, newName string) (err error) {
@@ -47,13 +48,19 @@ func Rename(oldName string, newName string) (err error) {
 	}
 	}
 
 
 	// test nginx configuration
 	// test nginx configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 		return fmt.Errorf("%s", output)
 	}
 	}
 
 
 	// reload nginx
 	// reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 		return fmt.Errorf("%s", output)
 	}
 	}

+ 9 - 2
internal/site/save.go

@@ -38,14 +38,21 @@ func Save(name string, content string, overwrite bool, envGroupId uint64, syncNo
 	enabledConfigFilePath := nginx.GetConfPath("sites-enabled", name)
 	enabledConfigFilePath := nginx.GetConfPath("sites-enabled", name)
 	if helper.FileExists(enabledConfigFilePath) {
 	if helper.FileExists(enabledConfigFilePath) {
 		// Test nginx configuration
 		// Test nginx configuration
-		output := nginx.TestConf()
+		var output string
+		output, err = nginx.TestConfig()
+		if err != nil {
+			return
+		}
 
 
 		if nginx.GetLogLevel(output) > nginx.Warn {
 		if nginx.GetLogLevel(output) > nginx.Warn {
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		}
 		}
 
 
 		if postAction == model.PostSyncActionReloadNginx {
 		if postAction == model.PostSyncActionReloadNginx {
-			output = nginx.Reload()
+			output, err = nginx.Reload()
+			if err != nil {
+				return
+			}
 			if nginx.GetLogLevel(output) > nginx.Warn {
 			if nginx.GetLogLevel(output) > nginx.Warn {
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 			}
 			}

+ 4 - 1
internal/stream/disable.go

@@ -35,7 +35,10 @@ func Disable(name string) (err error) {
 		return
 		return
 	}
 	}
 
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 8 - 2
internal/stream/enable.go

@@ -35,13 +35,19 @@ func Enable(name string) (err error) {
 	}
 	}
 
 
 	// Test nginx config, if not pass, then disable the site.
 	// Test nginx config, if not pass, then disable the site.
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		_ = os.Remove(enabledConfigFilePath)
 		_ = os.Remove(enabledConfigFilePath)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 	}
 
 
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 8 - 2
internal/stream/rename.go

@@ -49,13 +49,19 @@ func Rename(oldName string, newName string) (err error) {
 	}
 	}
 
 
 	// test nginx configuration
 	// test nginx configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 	}
 
 
 	// reload nginx
 	// reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
 	}

+ 9 - 2
internal/stream/save.go

@@ -37,15 +37,22 @@ func Save(name string, content string, overwrite bool, syncNodeIds []uint64, pos
 
 
 	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", name)
 	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", name)
 	if helper.FileExists(enabledConfigFilePath) {
 	if helper.FileExists(enabledConfigFilePath) {
+		var output string
 		// Test nginx configuration
 		// Test nginx configuration
-		output := nginx.TestConf()
+		output, err = nginx.TestConfig()
+		if err != nil {
+			return
+		}
 
 
 		if nginx.GetLogLevel(output) > nginx.Warn {
 		if nginx.GetLogLevel(output) > nginx.Warn {
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		}
 		}
 
 
 		if postAction == model.PostSyncActionReloadNginx {
 		if postAction == model.PostSyncActionReloadNginx {
-			output = nginx.Reload()
+			output, err = nginx.Reload()
+			if err != nil {
+				return
+			}
 			if nginx.GetLogLevel(output) > nginx.Warn {
 			if nginx.GetLogLevel(output) > nginx.Warn {
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 			}
 			}

+ 5 - 0
settings/nginx.go

@@ -11,6 +11,7 @@ type Nginx struct {
 	ReloadCmd       string   `json:"reload_cmd" protected:"true"`
 	ReloadCmd       string   `json:"reload_cmd" protected:"true"`
 	RestartCmd      string   `json:"restart_cmd" protected:"true"`
 	RestartCmd      string   `json:"restart_cmd" protected:"true"`
 	StubStatusPort  uint     `json:"stub_status_port" binding:"omitempty,min=1,max=65535"`
 	StubStatusPort  uint     `json:"stub_status_port" binding:"omitempty,min=1,max=65535"`
+	ContainerName   string   `json:"container_name" protected:"true"`
 }
 }
 
 
 var NginxSettings = &Nginx{}
 var NginxSettings = &Nginx{}
@@ -21,3 +22,7 @@ func (n *Nginx) GetStubStatusPort() uint {
 	}
 	}
 	return n.StubStatusPort
 	return n.StubStatusPort
 }
 }
+
+func (n *Nginx) RunningInAnotherContainer() bool {
+	return n.ContainerName != ""
+}