Repository: CherryHQ/cherry-studio
Pull request #5009: feat(websearch): HTTP basic auth support for Searxng
Author: login: cxw620
Created: 2025-04-17T15:46:11Z | Merged: 2025-04-18T17:58:04Z

https://github.com/CherryHQ/cherry-studio/issues/3300

为 Searxng 添加 HTTP Basic Auth 支持.

显示效果: 
![p9901](https://github.com/user-attachments/assets/e453d372-1013-4661-8559-ff4a25260ca5)

~~UI 苦手, 能用就行, 这个操作逻辑是我觉得还是比较明了的~~

请批评指正.


Diff:
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index b69df5d5ff3..accf1638155 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -1230,6 +1230,12 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "HTTP authentication",
+        "basic_auth.tip": "Applicable to instances deployed remotely (see the documentation). Currently, only the Basic scheme (RFC 7617) is supported.",
+        "basic_auth.user_name": "Username",
+        "basic_auth.user_name.tip": "Left empty to disable",
+        "basic_auth.password": "Password",
+        "basic_auth.password.tip": "",
         "charge": "Charge",
         "check": "Check",
         "check_all_keys": "Check All Keys",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index 09fb509005c..772d64d9270 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -1229,6 +1229,12 @@
         "api_key": "APIキー",
         "api_key.tip": "複数のキーはカンマで区切ります",
         "api_version": "APIバージョン",
+        "basic_auth": "HTTP 認証",
+        "basic_auth.tip": "サーバー展開によるインスタンスに適用されます（ドキュメントを参照）。現在はBasicスキーム（RFC7617）のみをサポートしています。",
+        "basic_auth.user_name": "ユーザー名",
+        "basic_auth.user_name.tip": "空欄で無効化",
+        "basic_auth.password": "パスワード",
+        "basic_auth.password.tip": "",
         "charge": "充電",
         "check": "チェック",
         "check_all_keys": "すべてのキーをチェック",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index 653494fbad7..ad26a716c60 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -1229,6 +1229,12 @@
         "api_key": "Ключ API",
         "api_key.tip": "Несколько ключей, разделенных запятыми",
         "api_version": "Версия API",
+        "basic_auth": "HTTP аутентификация",
+        "basic_auth.tip": "Применимо к экземплярам, развернутым через сервер (см. документацию). В настоящее время поддерживается только схема Basic (RFC7617).",
+        "basic_auth.user_name": "Имя пользователя",
+        "basic_auth.user_name.tip": "Оставить пустым для отключения",
+        "basic_auth.password": "Пароль",
+        "basic_auth.password.tip": "",
         "charge": "Пополнить",
         "check": "Проверить",
         "check_all_keys": "Проверить все ключи",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index 14f95123821..4af9bdb9932 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -1230,6 +1230,12 @@
         "api_key": "API 密钥",
         "api_key.tip": "多个密钥使用逗号分隔",
         "api_version": "API 版本",
+        "basic_auth": "HTTP 认证",
+        "basic_auth.tip": "适用于通过服务器部署的实例（参见文档）。目前仅支持 Basic 方案（RFC7617）。",
+        "basic_auth.user_name": "用户名",
+        "basic_auth.user_name.tip": "留空以禁用",
+        "basic_auth.password": "密码",
+        "basic_auth.password.tip": "",
         "charge": "充值",
         "check": "检查",
         "check_all_keys": "检查所有密钥",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index 37cd1498ba6..618a2251479 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -1229,6 +1229,12 @@
         "api_key": "API 金鑰",
         "api_key.tip": "多個金鑰使用逗號分隔",
         "api_version": "API 版本",
+        "basic_auth": "HTTP 認證",
+        "basic_auth.tip": "適用於透過伺服器部署的實例（請參閱文檔）。目前僅支援 Basic 方案（RFC7617）。",
+        "basic_auth.user_name": "用戶",
+        "basic_auth.user_name.tip": "留空以停用",
+        "basic_auth.password": "密碼",
+        "basic_auth.password.tip": "",
         "charge": "儲值",
         "check": "檢查",
         "check_all_keys": "檢查所有金鑰",
diff --git a/src/renderer/src/pages/settings/WebSearchSettings/WebSearchProviderSetting.tsx b/src/renderer/src/pages/settings/WebSearchSettings/WebSearchProviderSetting.tsx
index 25ba334fa0b..f19f192eb9b 100644
--- a/src/renderer/src/pages/settings/WebSearchSettings/WebSearchProviderSetting.tsx
+++ b/src/renderer/src/pages/settings/WebSearchSettings/WebSearchProviderSetting.tsx
@@ -5,14 +5,14 @@ import { formatApiKeys } from '@renderer/services/ApiService'
 import WebSearchService from '@renderer/services/WebSearchService'
 import { WebSearchProvider } from '@renderer/types'
 import { hasObjectKey } from '@renderer/utils'
-import { Avatar, Button, Divider, Flex, Input } from 'antd'
+import { Avatar, Button, Divider, Flex, Form, Input, Tooltip } from 'antd'
 import Link from 'antd/es/typography/Link'
 import { Info } from 'lucide-react'
 import { FC, useEffect, useState } from 'react'
 import { useTranslation } from 'react-i18next'
 import styled from 'styled-components'
 
-import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle, SettingTitle } from '..'
+import { SettingDivider, SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle, SettingTitle } from '..'
 import ApiCheckPopup from '../ProviderSettings/ApiCheckPopup'
 
 interface Props {
@@ -25,6 +25,8 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
   const [apiKey, setApiKey] = useState(provider.apiKey || '')
   const [apiHost, setApiHost] = useState(provider.apiHost || '')
   const [apiChecking, setApiChecking] = useState(false)
+  const [basicAuthUsername, setBasicAuthUsername] = useState(provider.basicAuthUsername || '')
+  const [basicAuthPassword, setBasicAuthPassword] = useState(provider.basicAuthPassword || '')
   const [apiValid, setApiValid] = useState(false)
 
   const webSearchProviderConfig = WEB_SEARCH_PROVIDER_CONFIG[provider.id]
@@ -49,6 +51,26 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
     }
   }
 
+  const onUpdateBasicAuthUsername = () => {
+    const currentValue = basicAuthUsername || ''
+    const savedValue = provider.basicAuthUsername || ''
+    if (currentValue !== savedValue) {
+      updateProvider({ ...provider, basicAuthUsername: basicAuthUsername })
+    } else {
+      setBasicAuthUsername(provider.basicAuthUsername || '')
+    }
+  }
+
+  const onUpdateBasicAuthPassword = () => {
+    const currentValue = basicAuthPassword || ''
+    const savedValue = provider.basicAuthPassword || ''
+    if (currentValue !== savedValue) {
+      updateProvider({ ...provider, basicAuthPassword: basicAuthPassword })
+    } else {
+      setBasicAuthPassword(provider.basicAuthPassword || '')
+    }
+  }
+
   async function checkSearch() {
     if (!provider) {
       window.message.error({
@@ -111,7 +133,9 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
   useEffect(() => {
     setApiKey(provider.apiKey ?? '')
     setApiHost(provider.apiHost ?? '')
-  }, [provider.apiKey, provider.apiHost])
+    setBasicAuthUsername(provider.basicAuthUsername ?? '')
+    setBasicAuthPassword(provider.basicAuthPassword ?? '')
+  }, [provider.apiKey, provider.apiHost, provider.basicAuthUsername, provider.basicAuthPassword])
 
   return (
     <>
@@ -176,6 +200,50 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
               {apiChecking ? <LoadingOutlined spin /> : apiValid ? <CheckOutlined /> : t('settings.websearch.check')}
             </Button>
           </Flex>
+          <SettingDivider style={{ marginTop: 12, marginBottom: 12 }} />
+          <SettingSubtitle style={{ marginTop: 5, marginBottom: 10 }}>
+            {t('settings.provider.basic_auth')}
+            <Tooltip title={t('settings.provider.basic_auth.tip')} placement="right">
+              <Info size={16} color="var(--color-icon)" style={{ marginLeft: 5, cursor: 'pointer' }} />
+            </Tooltip>
+          </SettingSubtitle>
+          <Flex>
+            <Form
+              layout="inline"
+              initialValues={{
+                username: basicAuthUsername,
+                password: basicAuthPassword
+              }}
+              onValuesChange={(changedValues) => {
+                // Update local state when form values change
+                if ('username' in changedValues) {
+                  setBasicAuthUsername(changedValues.username || '')
+                }
+                if ('password' in changedValues) {
+                  setBasicAuthPassword(changedValues.password || '')
+                }
+              }}>
+              <Form.Item label={t('settings.provider.basic_auth.user_name')} name="username">
+                <Input
+                  placeholder={t('settings.provider.basic_auth.user_name.tip')}
+                  onBlur={onUpdateBasicAuthUsername}
+                />
+              </Form.Item>
+              <Form.Item
+                label={t('settings.provider.basic_auth.password')}
+                name="password"
+                rules={[{ required: !!basicAuthUsername, validateTrigger: ['onBlur', 'onChange'] }]}
+                help=""
+                hidden={!basicAuthUsername}>
+                <Input.Password
+                  placeholder={t('settings.provider.basic_auth.password.tip')}
+                  onBlur={onUpdateBasicAuthPassword}
+                  disabled={!basicAuthUsername}
+                  visibilityToggle={true}
+                />
+              </Form.Item>
+            </Form>
+          </Flex>
         </>
       )}
     </>
diff --git a/src/renderer/src/providers/WebSearchProvider/SearxngProvider.ts b/src/renderer/src/providers/WebSearchProvider/SearxngProvider.ts
index ad877ba1bd6..0e95c12cc77 100644
--- a/src/renderer/src/providers/WebSearchProvider/SearxngProvider.ts
+++ b/src/renderer/src/providers/WebSearchProvider/SearxngProvider.ts
@@ -2,6 +2,7 @@ import { SearxngClient } from '@agentic/searxng'
 import { WebSearchState } from '@renderer/store/websearch'
 import { WebSearchProvider, WebSearchResponse } from '@renderer/types'
 import axios from 'axios'
+import ky from 'ky'
 
 import BaseWebSearchProvider from './BaseWebSearchProvider'
 
@@ -9,6 +10,8 @@ export default class SearxngProvider extends BaseWebSearchProvider {
   private searxng: SearxngClient
   private engines: string[] = []
   private readonly apiHost: string
+  private readonly basicAuthUsername?: string
+  private readonly basicAuthPassword?: string
   private isInitialized = false
 
   constructor(provider: WebSearchProvider) {
@@ -16,9 +19,22 @@ export default class SearxngProvider extends BaseWebSearchProvider {
     if (!provider.apiHost) {
       throw new Error('API host is required for SearxNG provider')
     }
+
     this.apiHost = provider.apiHost
+    this.basicAuthUsername = provider.basicAuthUsername
+    this.basicAuthPassword = provider.basicAuthPassword ? provider.basicAuthPassword : ''
+
     try {
-      this.searxng = new SearxngClient({ apiBaseUrl: this.apiHost })
+      // `ky` do not support basic auth directly
+      const headers = this.basicAuthUsername
+        ? {
+            Authorization: `Basic ` + btoa(`${this.basicAuthUsername}:${this.basicAuthPassword}`)
+          }
+        : undefined
+      this.searxng = new SearxngClient({
+        apiBaseUrl: this.apiHost,
+        ky: ky.create({ headers })
+      })
     } catch (error) {
       throw new Error(
         `Failed to initialize SearxNG client: ${error instanceof Error ? error.message : 'Unknown error'}`
@@ -29,9 +45,16 @@ export default class SearxngProvider extends BaseWebSearchProvider {
   private async initEngines(): Promise<void> {
     try {
       console.log(`Initializing SearxNG with API host: ${this.apiHost}`)
+      const auth = this.basicAuthUsername
+        ? {
+            username: this.basicAuthUsername,
+            password: this.basicAuthPassword ? this.basicAuthPassword : ''
+          }
+        : undefined
       const response = await axios.get(`${this.apiHost}/config`, {
         timeout: 5000,
-        validateStatus: (status) => status === 200 // 仅接受 200 状态码
+        validateStatus: (status) => status === 200, // 仅接受 200 状态码
+        auth
       })
 
       if (!response.data) {
diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts
index b0280e00745..2a1318b4a6f 100644
--- a/src/renderer/src/store/migrate.ts
+++ b/src/renderer/src/store/migrate.ts
@@ -1236,6 +1236,19 @@ const migrateConfig = {
     } catch (error) {
       return state
     }
+  },
+  '98': (state: RootState) => {
+    try {
+      if (state.websearch && state.websearch.providers) {
+        state.websearch.providers.forEach((provider) => {
+          provider.basicAuthUsername = ''
+          provider.basicAuthPassword = ''
+        })
+      }
+      return state
+    } catch (error) {
+      return state
+    }
   }
 }
 
diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts
index ec1f5f96ee4..5d3b8f25396 100644
--- a/src/renderer/src/types/index.ts
+++ b/src/renderer/src/types/index.ts
@@ -342,6 +342,8 @@ export type WebSearchProvider = {
   apiHost?: string
   engines?: string[]
   url?: string
+  basicAuthUsername?: string
+  basicAuthPassword?: string
   contentLimit?: number
   usingBrowser?: boolean
 }


Reviews:
user: login: DeJeune
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-18T10:02:49Z
user: login: cxw620
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T11:31:44Z
user: login: DeJeune
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T11:35:39Z
user: login: cxw620
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T11:47:11Z
user: login: DeJeune
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T11:52:53Z

Review comments:
diff_hunk: @@ -176,6 +201,35 @@ const WebSearchProviderSetting: FC<Props> = ({ provider: _provider }) => {
               {apiChecking ? <LoadingOutlined spin /> : apiValid ? <CheckOutlined /> : t('settings.websearch.check')}
             </Button>
           </Flex>
+          <SettingDivider style={{ marginTop: 12, marginBottom: 12 }} />
+          <SettingRow>
+            {t('settings.provider.basic_auth')}
path: src/renderer/src/pages/settings/WebSearchSettings/WebSearchProviderSetting.tsx
user: login: DeJeune
body: 标题和输入框分行，学上面一样用`SettingSubtitle`组件
created_at: 2025-04-17T16:29:33Z
author_association: COLLABORATOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/en-us.json
user: login: DeJeune
body: 我觉得Basic Auth这个词太专业了，能不能换个用户都懂的术语
created_at: 2025-04-17T16:34:19Z
author_association: COLLABORATOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API 密钥",
         "api_key.tip": "多个密钥使用逗号分隔",
         "api_version": "API 版本",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/zh-cn.json
user: login: DeJeune
body: 中文翻译一下
created_at: 2025-04-17T16:34:39Z
author_association: COLLABORATOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/en-us.json
user: login: cxw620
body: 但是 HTTP Basic Auth 是个专有名词, 翻译成 `基本认证`, 嘶...

严格意义上, `HTTP Authentication` 翻译成 `HTTP 认证` 是 MDN 文档的官方译法, 这里按 `HTTP Auth` / `HTTP 认证`, 然后加个注释 `只支持 Basic 验证方案 (RFC 7617)` 可能会更好一点? 再给个参考文档怎么配置 Nginx 就行:

命令行执行:

```sh
# 假设 Nginx 配置文件保存于 /etc/nginx/conf.d 下
echo "example_name:$(openssl passwd -5 'example_password')" > /etc/nginx/conf.d/search.htpasswd
```

随后配置反向代理, 参考如下:

```conf
server
{
    listen 443 ssl;

    server_name search.example.com;

    # index index.html;
    # root /data/www/default;

    # SSL
    ssl_certificate    /path/to/your/cert/fullchain.pem;
    ssl_certificate_key    /path/to/your/cert/privkey.pem;

    # HSTS
    # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

    # Favicon
    location / {
        # 在 location 块添加下面两行, 其他按实际情况设置
        auth_basic "Please enter your username and password";
        auth_basic_user_file /etc/nginx/conf.d/search.htpasswd;

        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        proxy_pass http://127.0.0.1:8000;
        client_max_body_size 0;
    }

    # access_log  ...;
    # error_log  ...;
}
```

created_at: 2025-04-18T11:31:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/en-us.json
user: login: DeJeune
body: > 但是 HTTP Basic Auth 是个专有名词, 翻译成 `基本认证`, 嘶...
> 
> 严格意义上, `HTTP Authentication` 翻译成 `HTTP 认证` 是 MDN 文档的官方译法, 这里按 `HTTP Auth` / `HTTP 认证`, 然后加个注释 `只支持 Basic 验证方案 (RFC 7617)` 可能会更好一点? 再给个参考文档怎么配置 Nginx 就行:
> 
> 命令行执行:
> 
> ```shell
> # 假设 Nginx 配置文件保存于 /etc/nginx/conf.d 下
> echo "example_name:$(openssl passwd -5 'example_password')" > /etc/nginx/conf.d/search.htpasswd
> ```
> 
> 随后配置反向代理, 参考如下:
> 
> ```
> server
> {
>     listen 443 ssl;
> 
>     server_name search.example.com;
> 
>     # index index.html;
>     # root /data/www/default;
> 
>     # SSL
>     ssl_certificate    /path/to/your/cert/fullchain.pem;
>     ssl_certificate_key    /path/to/your/cert/privkey.pem;
> 
>     # HSTS
>     # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
> 
>     # Favicon
>     location / {
>         # 在 location 块添加下面两行, 其他按实际情况设置
>         auth_basic "Please enter your username and password";
>         auth_basic_user_file /etc/nginx/conf.d/search.htpasswd;
> 
>         proxy_http_version 1.1;
>         proxy_set_header Connection "";
>         proxy_redirect off;
>         proxy_set_header Host $host;
>         proxy_set_header X-Forwarded-For $proxy_protocol_addr;
>         proxy_pass http://127.0.0.1:8000;
>         client_max_body_size 0;
>     }
> 
>     # access_log  ...;
>     # error_log  ...;
> }
> ```

合理，那你提交个commit，修改一下翻译方法？
nginx中ssl应该是可选的，如果生成证书和私钥，又会让用户去维护let's encrypt证书失效的问题
created_at: 2025-04-18T11:35:39Z
author_association: COLLABORATOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/en-us.json
user: login: cxw620
body: > nginx中ssl应该是可选的，如果生成证书和私钥，又会让用户去维护let's encrypt证书失效的问题

这个应该就不是我们需要考虑的问题了吧, 文档给个 Nginx 参考, 有公网部署需求应该不至于 Nginx / Caddy 完全不会使吧... 退一步, 不要 HTTPS 自用的话问题也不大, 主要还是为了防止暴露在公网环境的实例被 fofa 之类的玩意扫描到后被滥用.
created_at: 2025-04-18T11:47:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1230,6 +1230,11 @@
         "api_key": "API Key",
         "api_key.tip": "Multiple keys separated by commas",
         "api_version": "API Version",
+        "basic_auth": "Basic Auth",
path: src/renderer/src/i18n/locales/en-us.json
user: login: DeJeune
body: 可
created_at: 2025-04-18T11:52:53Z
author_association: COLLABORATOR

PR comments:
user: login: DeJeune
created_at: 2025-04-17T16:33:09Z
body: 还有个问题，需要把帐号和密码保存到redux里。

https://github.com/CherryHQ/cherry-studio/blob/main/src/renderer/src/store/websearch.ts

然后要写迁移逻辑，因为旧版本升级上来schema中没有这两个字段。

https://github.com/CherryHQ/cherry-studio/blob/main/src/renderer/src/store/migrate.ts
author_association: COLLABORATOR
user: login: cxw620
created_at: 2025-04-17T19:41:29Z
body: > 还有个问题，需要把帐号和密码保存到redux里。

没理解错的话 onUpdateBasicAuthUsername -> updateProvider 存了

> 然后要写迁移逻辑，因为旧版本升级上来schema中没有这两个字段。

照葫芦画瓢写好了

author_association: CONTRIBUTOR
user: login: eeee0717
created_at: 2025-04-18T10:44:06Z
body: searxng哪个配置可以设置auth？我测一下
author_association: COLLABORATOR
user: login: cxw620
created_at: 2025-04-18T11:13:44Z
body: > searxng哪个配置可以设置auth？我测一下

本体不支持, 毕竟明文 HTTP Basic Auth 意义不大.

需要前面放一个 nginx 之类的玩意.
author_association: CONTRIBUTOR
user: login: eeee0717
created_at: 2025-04-18T11:25:55Z
body: 那你如果测试通过了就merge吧
author_association: COLLABORATOR
user: login: DeJeune
created_at: 2025-04-18T11:27:53Z
body: > > searxng哪个配置可以设置auth？我测一下
> 
> 本体不支持, 毕竟明文 HTTP Basic Auth 意义不大.
> 
> 需要前面放一个 nginx 之类的玩意.

https://github.com/CherryHQ/cherry-studio-docs

能否在文档中更新一个配nginx的教程 大部分用户配不明白

author_association: COLLABORATOR
user: login: cxw620
created_at: 2025-04-18T11:32:22Z
body: > > > searxng哪个配置可以设置auth？我测一下
> > 
> > 
> > 本体不支持, 毕竟明文 HTTP Basic Auth 意义不大.
> > 需要前面放一个 nginx 之类的玩意.
> 
> https://github.com/CherryHQ/cherry-studio-docs
> 
> 能否在文档中更新一个配nginx的教程 大部分用户配不明白

可
author_association: CONTRIBUTOR
user: login: cxw620
created_at: 2025-04-18T14:34:46Z
body: > > > > searxng哪个配置可以设置auth？我测一下
> > > 
> > > 
> > > 本体不支持, 毕竟明文 HTTP Basic Auth 意义不大.
> > > 需要前面放一个 nginx 之类的玩意.
> > 
> > 
> > https://github.com/CherryHQ/cherry-studio-docs
> > 能否在文档中更新一个配nginx的教程 大部分用户配不明白
> 
> 可

https://github.com/CherryHQ/cherry-studio-docs/pull/50
author_association: CONTRIBUTOR
user: login: cxw620
created_at: 2025-04-18T17:40:48Z
body: > 那你如果测试通过了就merge吧

我这本地用着没啥问题了

![图片](https://github.com/user-attachments/assets/a8db3f01-3400-4909-9a9a-4967aa7770f4)

author_association: CONTRIBUTOR