优化安装脚本
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
HOST=0.0.0.0
|
||||
PORT=3000
|
||||
PORT=3051
|
||||
REFRESH_INTERVAL=5000
|
||||
|
||||
# Valkey/Redis Cache Configuration
|
||||
|
||||
118
install.sh
118
install.sh
@@ -121,4 +121,122 @@ else
|
||||
echo -e "Check logs with: ${BLUE}journalctl -u data-wall -xe${NC}"
|
||||
fi
|
||||
|
||||
# 10. Reverse Proxy Configuration
|
||||
echo -ne "${YELLOW}Do you want to configure a reverse proxy (Nginx/Caddy)? (y/n): ${NC}"
|
||||
read -r CONF_PROXY
|
||||
if [[ "$CONF_PROXY" =~ ^[Yy]$ ]]; then
|
||||
echo -e "${BLUE}=== Reverse Proxy Configuration ===${NC}"
|
||||
|
||||
# Get Domain
|
||||
echo -ne "Enter your domain name (e.g., monitor.example.com): "
|
||||
read -r DOMAIN
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
echo -e "${RED}Error: Domain cannot be empty. Skipping proxy configuration.${NC}"
|
||||
else
|
||||
# Get Port from .env
|
||||
PORT=$(grep "^PORT=" .env | cut -d'=' -f2)
|
||||
PORT=${PORT:-3000}
|
||||
|
||||
# Choose Proxy
|
||||
echo -e "Select Proxy Type:"
|
||||
echo -e " 1) Caddy (Automatic SSL, easy to use)"
|
||||
echo -e " 2) Nginx (Advanced, manual SSL)"
|
||||
echo -ne "Choose (1/2): "
|
||||
read -r PROXY_TYPE
|
||||
|
||||
# Enable HTTPS?
|
||||
echo -ne "Enable HTTPS (SSL)? (y/n): "
|
||||
read -r ENABLE_HTTPS
|
||||
|
||||
if [ "$PROXY_TYPE" == "1" ]; then
|
||||
# Caddy Config
|
||||
CADDY_FILE="Caddyfile"
|
||||
echo -e "${BLUE}Generating Caddyfile...${NC}"
|
||||
|
||||
if [[ "$ENABLE_HTTPS" =~ ^[Yy]$ ]]; then
|
||||
cat <<EOF > "$CADDY_FILE"
|
||||
$DOMAIN {
|
||||
reverse_proxy localhost:$PORT
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > "$CADDY_FILE"
|
||||
http://$DOMAIN {
|
||||
reverse_proxy localhost:$PORT
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
chown "$REAL_USER":"$REAL_USER" "$CADDY_FILE"
|
||||
echo -e "${GREEN}Caddyfile generated at $PROJECT_DIR/$CADDY_FILE${NC}"
|
||||
echo -e "${YELLOW}Tip: Ensure Caddy is installed and pointing to this file.${NC}"
|
||||
|
||||
elif [ "$PROXY_TYPE" == "2" ]; then
|
||||
# Nginx Config
|
||||
echo -ne "Enter Nginx configuration export path (default: ./${DOMAIN}.conf): "
|
||||
read -r NGINX_PATH
|
||||
NGINX_PATH=${NGINX_PATH:-"./${DOMAIN}.conf"}
|
||||
|
||||
echo -e "${BLUE}Generating Nginx configuration...${NC}"
|
||||
|
||||
if [[ "$ENABLE_HTTPS" =~ ^[Yy]$ ]]; then
|
||||
echo -ne "Enter SSL Certificate Path: "
|
||||
read -r SSL_CERT
|
||||
echo -ne "Enter SSL Key Path: "
|
||||
read -r SSL_KEY
|
||||
|
||||
cat <<EOF > "$NGINX_PATH"
|
||||
server {
|
||||
listen 80;
|
||||
server_name $DOMAIN;
|
||||
return 301 https://\$host\$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name $DOMAIN;
|
||||
|
||||
ssl_certificate $SSL_CERT;
|
||||
ssl_certificate_key $SSL_KEY;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:$PORT;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > "$NGINX_PATH"
|
||||
server {
|
||||
listen 80;
|
||||
server_name $DOMAIN;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:$PORT;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
chown "$REAL_USER":"$REAL_USER" "$NGINX_PATH"
|
||||
echo -e "${GREEN}Nginx config generated at $NGINX_PATH${NC}"
|
||||
echo -e "${YELLOW}Tip: You can symlink this to /etc/nginx/sites-enabled/ to activate.${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Unknown proxy type selected. Skipping.${NC}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}================================================${NC}"
|
||||
echo -e "${GREEN}Setup completed successfully!${NC}"
|
||||
|
||||
@@ -395,9 +395,12 @@
|
||||
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);">
|
||||
<option value="dark">默认夜间模式</option>
|
||||
<option value="light">默认白天模式</option>
|
||||
<option value="auto">跟随浏览器/系统</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 15px; display: flex; align-items: center; gap: 10px;">
|
||||
<input type="checkbox" id="show95BandwidthInput" style="width: 18px; height: 18px; cursor: pointer;">
|
||||
<label for="show95BandwidthInput" style="cursor: pointer; user-select: none;">24h趋势图默认显示 95计费线</label>
|
||||
</div>
|
||||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||||
<button class="btn btn-add" id="btnSaveSiteSettings">保存设置</button>
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
logoText: document.getElementById('logoText'),
|
||||
logoIconContainer: document.getElementById('logoIconContainer'),
|
||||
defaultThemeInput: document.getElementById('defaultThemeInput'),
|
||||
show95BandwidthInput: document.getElementById('show95BandwidthInput'),
|
||||
// Auth & Theme elements
|
||||
themeToggle: document.getElementById('themeToggle'),
|
||||
sunIcon: document.querySelector('.sun-icon'),
|
||||
@@ -218,6 +219,7 @@
|
||||
dom.siteTitleInput.value = window.SITE_SETTINGS.title || '';
|
||||
dom.logoUrlInput.value = window.SITE_SETTINGS.logo_url || '';
|
||||
dom.defaultThemeInput.value = window.SITE_SETTINGS.default_theme || 'dark';
|
||||
dom.show95BandwidthInput.checked = !!window.SITE_SETTINGS.show_95_bandwidth;
|
||||
}
|
||||
|
||||
loadSiteSettings();
|
||||
@@ -903,9 +905,19 @@
|
||||
|
||||
// Update inputs
|
||||
dom.pageNameInput.value = settings.page_name || '';
|
||||
dom.siteTitleInput.value = settings.title || '';
|
||||
dom.logoUrlInput.value = settings.logo_url || '';
|
||||
dom.defaultThemeInput.value = settings.default_theme || 'dark';
|
||||
if (settings.title) dom.siteTitleInput.value = settings.title;
|
||||
if (settings.logo_url) dom.logoUrlInput.value = settings.logo_url;
|
||||
if (settings.default_theme) dom.defaultThemeInput.value = settings.default_theme;
|
||||
if (settings.show_95_bandwidth !== undefined) {
|
||||
dom.show95BandwidthInput.checked = !!settings.show_95_bandwidth;
|
||||
if (networkChart) {
|
||||
networkChart.showP95 = !!settings.show_95_bandwidth;
|
||||
if (dom.legendP95) {
|
||||
dom.legendP95.classList.toggle('disabled', !networkChart.showP95);
|
||||
}
|
||||
networkChart.draw();
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to UI
|
||||
applySiteSettings(settings);
|
||||
@@ -957,6 +969,17 @@
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
||||
// P95 setting
|
||||
if (settings.show_95_bandwidth !== undefined) {
|
||||
if (networkChart) {
|
||||
networkChart.showP95 = !!settings.show_95_bandwidth;
|
||||
if (dom.legendP95) {
|
||||
dom.legendP95.classList.toggle('disabled', !networkChart.showP95);
|
||||
}
|
||||
networkChart.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSiteSettings() {
|
||||
@@ -970,7 +993,8 @@
|
||||
page_name: dom.pageNameInput.value.trim(),
|
||||
title: dom.siteTitleInput.value.trim(),
|
||||
logo_url: dom.logoUrlInput.value.trim(),
|
||||
default_theme: dom.defaultThemeInput.value
|
||||
default_theme: dom.defaultThemeInput.value,
|
||||
show_95_bandwidth: dom.show95BandwidthInput.checked ? 1 : 0
|
||||
};
|
||||
|
||||
dom.btnSaveSiteSettings.disabled = true;
|
||||
|
||||
@@ -36,6 +36,15 @@ async function checkAndFixDatabase() {
|
||||
}
|
||||
console.log(`[Database Integrity] ✅ Missing tables created.`);
|
||||
}
|
||||
|
||||
// Check for new columns in site_settings
|
||||
const [columns] = await db.query("SHOW COLUMNS FROM site_settings");
|
||||
const columnNames = columns.map(c => c.Field);
|
||||
if (!columnNames.includes('show_95_bandwidth')) {
|
||||
console.log(`[Database Integrity] ⚠️ Missing column 'show_95_bandwidth' in 'site_settings'. Adding it...`);
|
||||
await db.query("ALTER TABLE site_settings ADD COLUMN show_95_bandwidth TINYINT(1) DEFAULT 0 AFTER default_theme");
|
||||
console.log(`[Database Integrity] ✅ Column 'show_95_bandwidth' added.`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Database Integrity] ❌ Error checking integrity:', err.message);
|
||||
}
|
||||
@@ -75,12 +84,13 @@ async function createTable(tableName) {
|
||||
title VARCHAR(255) DEFAULT '数据可视化展示大屏',
|
||||
logo_url TEXT,
|
||||
default_theme VARCHAR(20) DEFAULT 'dark',
|
||||
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
await db.query(`
|
||||
INSERT IGNORE INTO site_settings (id, page_name, title, default_theme)
|
||||
VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark')
|
||||
INSERT IGNORE INTO site_settings (id, page_name, title, default_theme, show_95_bandwidth)
|
||||
VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark', 0)
|
||||
`);
|
||||
break;
|
||||
case 'traffic_stats':
|
||||
|
||||
@@ -216,12 +216,13 @@ app.post('/api/setup/init', async (req, res) => {
|
||||
title VARCHAR(255) DEFAULT '数据可视化展示大屏',
|
||||
logo_url TEXT,
|
||||
default_theme VARCHAR(20) DEFAULT 'dark',
|
||||
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
await connection.query(`
|
||||
INSERT IGNORE INTO site_settings (id, page_name, title, default_theme)
|
||||
VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark')
|
||||
INSERT IGNORE INTO site_settings (id, page_name, title, default_theme, show_95_bandwidth)
|
||||
VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark', 0)
|
||||
`);
|
||||
|
||||
await connection.end();
|
||||
@@ -487,7 +488,8 @@ app.get('/api/settings', async (req, res) => {
|
||||
return res.json({
|
||||
page_name: '数据可视化展示大屏',
|
||||
title: '数据可视化展示大屏',
|
||||
logo_url: null
|
||||
logo_url: null,
|
||||
show_95_bandwidth: 0
|
||||
});
|
||||
}
|
||||
res.json(rows[0]);
|
||||
@@ -499,18 +501,19 @@ app.get('/api/settings', async (req, res) => {
|
||||
|
||||
// Update site settings
|
||||
app.post('/api/settings', requireAuth, async (req, res) => {
|
||||
const { page_name, title, logo_url, default_theme } = req.body;
|
||||
try {
|
||||
await db.query(
|
||||
`INSERT INTO site_settings (id, page_name, title, logo_url, default_theme)
|
||||
VALUES (1, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
page_name = VALUES(page_name),
|
||||
title = VALUES(title),
|
||||
logo_url = VALUES(logo_url),
|
||||
default_theme = VALUES(default_theme)`,
|
||||
[page_name, title, logo_url, default_theme]
|
||||
);
|
||||
const { page_name, title, logo_url, default_theme, show_95_bandwidth } = req.body;
|
||||
try {
|
||||
await db.query(
|
||||
`INSERT INTO site_settings (id, page_name, title, logo_url, default_theme, show_95_bandwidth)
|
||||
VALUES (1, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
page_name = VALUES(page_name),
|
||||
title = VALUES(title),
|
||||
logo_url = VALUES(logo_url),
|
||||
default_theme = VALUES(default_theme),
|
||||
show_95_bandwidth = VALUES(show_95_bandwidth)`,
|
||||
[page_name, title, logo_url, default_theme, show_95_bandwidth ? 1 : 0]
|
||||
);
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error('Error updating settings:', err);
|
||||
|
||||
Reference in New Issue
Block a user