Difyをセルフホスト環境(ローカルやVPS)で運用していると、「ここを少し使いやすくしたい」「独自のダッシュボードを追加したい」といった要望が出てくることがあります。
この記事では、Docker環境で構築したDifyのフロントエンド(Next.js)をカスタマイズし、モバイル版での操作性向上と、独自ダッシュボード画面の追加を行う具体的な手順を解説します。
今回のカスタマイズ内容
以下の2点を実装します。
- モバイル版UIの改善: チャット履歴を選択した際に、自動的にサイドバーが閉じるように修正します。(現状は手動で閉じる必要があり、操作性が良くありません)
- 独自ダッシュボードの追加: 複数のDify環境や関連ツールへのリンクをまとめた、簡易的なダッシュボード画面(HTML)を設置し、Basic認証で保護します。

1. フロントエンド(React)の修正
Difyのフロントエンドコードを修正し、モバイルでの挙動を改善します。
サイドバーコンポーネントの修正
編集ファイル:dify/web/app/components/base/chat/chat-with-history/sidebar/index.tsx
チャット切り替え時に、親コンポーネントから渡された「閉じる関数(onClose)」を実行するように変更します。
23行目付近~
type Props = {
isPanel?: boolean
+ onClose?: () => void
}
- const Sidebar = ({ isPanel }: Props) => {
+ const Sidebar = ({ isPanel, onClose }: Props) => {
const { t } = useTranslation()
const {
appData,
handleNewConversation,
pinnedConversationList,
conversationList,
currentConversationId,
handleChangeConversation,
handlePinConversation,
handleUnpinConversation,
conversationRenaming,
handleRenameConversation,
handleDeleteConversation,
sidebarCollapseState,
handleSidebarCollapse,
isMobile,
isResponding,
} = useChatWithHistoryContext()
52行目付近~
const handleOperate = useCallback((type: string, item: ConversationItem) => {
if (type === 'pin')
handlePinConversation(item.id)
if (type === 'unpin')
handleUnpinConversation(item.id)
if (type === 'delete')
setShowConfirm(item)
if (type === 'rename')
setShowRename(item)
}, [handlePinConversation, handleUnpinConversation])
+ const handleChangeConversationWrapper = useCallback((conversationId: string) => {
+ handleChangeConversation(conversationId)
+ if (onClose)
+ onClose()
+ }, [handleChangeConversation, onClose])
const handleCancelConfirm = useCallback(() => {
setShowConfirm(null)
}, [])
114行目付近~
<div className='h-0 grow space-y-2 overflow-y-auto px-3 pt-4'>
{/* pinned list */}
{!!pinnedConversationList.length && (
<div className='mb-4'>
<List
isPin
title={t('share.chat.pinnedTitle') || ''}
list={pinnedConversationList}
- onChangeConversation={handleChangeConversation}
+ onChangeConversation={handleChangeConversationWrapper}
onOperate={handleOperate}
currentConversationId={currentConversationId}
/>
</div>
)}
{!!conversationList.length && (
<List
title={(pinnedConversationList.length && t('share.chat.unpinnedTitle')) || ''}
list={conversationList}
- onChangeConversation={handleChangeConversation}
+ onChangeConversation={handleChangeConversationWrapper}
onOperate={handleOperate}
currentConversationId={currentConversationId}
/>
)}
モバイルヘッダーでの呼び出し修正
編集ファイル:dify/web/app/components/base/chat/chat-with-history/header-in-mobile.tsx
サイドバー呼び出し時に、閉じるための関数を渡します。
104行目付近~
{showSidebar && (
<div className='fixed inset-0 z-50 flex bg-background-overlay p-1'
onClick={() => setShowSidebar(false)}
>
<div className='flex h-full w-[calc(100vw_-_40px)] rounded-xl bg-components-panel-bg shadow-lg backdrop-blur-sm' onClick={e => e.stopPropagation()}>
- <Sidebar />
+ <Sidebar isPanel onClose={() => setShowSidebar(false)} />
</div>
</div>
)}
2. 独自ダッシュボードの追加
Nginxコンテナを利用して、静的なHTMLファイル(ダッシュボード)を配信する設定を追加します。
HTMLファイルの作成
# ディレクトリ作成
mkdir -p dify/docker/nginx/html
# dashboard.htmlの中身を作成
nano html/dashboard.html
Nginx設定の修正とBasic認証
ダッシュボードへのアクセス制限(Basic認証)を設定します。
# 認証ツールのインストール
sudo apt update &&
sudo apt install apache2-utils
パスワードファイルの作成
sudo htpasswd -c dify/docker/nginx/conf.d/.htpasswd <ユーザー名>
Nginxの設定ファイル(dify/docker/nginx/conf.d/default.conf等 ※環境による)に以下を追記します。
ルーティングとBasic認証の追加
location / {
proxy_pass http://web:3000;
include proxy.conf;
}
+ location /dashboard {
+ auth_basic "Restricted Access";
+ auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
+ root /usr/share/nginx/html;
+ index dashboard.html;
+ try_files /dashboard.html $uri $uri/ =404;
+ }
+
# placeholder for acme challenge location
${ACME_CHALLENGE_LOCATION}
3. Docker環境への反映
修正したフロントエンドコードを反映させるため、Docker Composeの設定を変更し、イメージをビルドし直します。
docker-compose.yamlの修正
デフォルトではDocker Hubのイメージを使用していますが、ローカルのソースコードからビルドするように変更します。
docker-compose.yaml (webサービス部分)
# Frontend web application.
web:
- image: langgenius/dify-web:1.2.0
+ build:
+ context: ../web
+ dockerfile: Dockerfile
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
APP_API_URL: ${APP_API_URL:-}
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-}
PM2_INSTANCES: ${PM2_INSTANCES:-2}
LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-5}
また、NginxサービスにHTMLファイルをマウントする設定を追加します。
691行目付近~ (nginxサービス部分)
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template
- ./nginx/proxy.conf.template:/etc/nginx/proxy.conf.template
- ./nginx/https.conf.template:/etc/nginx/https.conf.template
- ./nginx/conf.d:/etc/nginx/conf.d
+ - ./nginx/html:/usr/share/nginx/html
- ./nginx/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- ./nginx/ssl:/etc/ssl # cert dir (legacy)
- ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container)
- ./volumes/certbot/conf:/etc/letsencrypt
- ./volumes/certbot/www:/var/www/html
ビルドと再起動
設定変更後、コンテナを再ビルドして起動します。
cd dify/docker
docker compose up -d --build
まとめ
これで、モバイル版での操作性が向上し、管理用のダッシュボードも追加されました。
Difyはオープンソースであるため、このように自社の運用に合わせて柔軟にUI/UXを改善できるのが大きな魅力です。ぜひ、使いやすい環境構築にチャレンジしてみてください。
【推奨】業務システム化に有効なアイテム
生成AIを学ぶ



システム化のパートナー



VPSサーバの選定





コメント