T面板 - Linux 网站管理面板
🛡️
安全状态:已启用自动更新
系统每日 03:00 自动执行安全更新
安全中心
T面板每日凌晨 03:00 自动执行 apt-get update && apt-get upgrade -y,修复已知安全漏洞。
最近执行:-
/
文件:
当前权限:
快速预设:
📤
点击或拖拽文件到这里上传
v1.3.41: 仅上传,不解压(zip/tar.gz 请在文件列表手动解压)
⏰ 定时任务
| 任务名称 |
站点 |
执行周期 |
命令 |
状态 |
上次执行 |
操作 |
📦 软件市场
一键安装建站必备环境。安装过程中会显示实时进度。
⬆️ 手动升级
📦
拖拽安装包到这里,或点击选择文件
支持 tpanel-v*.zip 格式安装包
⏪ 版本回滚
升级前会自动备份当前版本,可以随时回滚
数据库:
⚠️ 修改后请同步更新站点配置文件(如 wp-config.php、.env 等)
将通过 Let's Encrypt 自动申请 SSL 证书(HTTP 验证)。
证书有效期 90 天,自动续期。
500KB 用 textarea,否则用 CM5
const MAX_CM_SIZE = 500 * 1024;
if (content.length > MAX_CM_SIZE) {
console.warn('[CM5] file too large, fallback to textarea');
ta.value = content;
ta.style.display = 'block';
container.style.display = 'none';
return;
}
// 根据后缀选 mode
const ext = (filepath.split('.').pop() || '').toLowerCase();
const mode = modeMap[ext] || 'text/plain';
// 宝塔风格主题:深色用 material-darker,浅色用 default
const theme = isDark ? 'material-darker' : 'default';
try {
_cmEditor = CodeMirror(container, {
value: content,
mode: mode,
theme: theme,
lineNumbers: true,
indentUnit: 4,
tabSize: 4,
indentWithTabs: false,
autoCloseBrackets: true,
matchBrackets: true,
styleActiveLine: true,
lineWrapping: true,
extraKeys: {
'Ctrl-S': function() { saveFile(); },
'Cmd-S': function() { saveFile(); }
}
});
// 强制 refresh(modal 刚打开时 width 可能为 0)
setTimeout(() => { try { _cmEditor.refresh(); } catch(e){} }, 100);
console.log('[v1.3.42 CM5] init done');
} catch (e) {
console.error('[CM5] init failed, fallback textarea:', e);
_cmEditor = null;
ta.value = content;
ta.style.display = 'block';
container.style.display = 'none';
}
}
}
const ta = document.getElementById('fileEditor');
return ta ? ta.value : '';
}
// =====================
// v1.3.39+ 在线升级
// =====================
async function loadUpgradePage() {
const d = await api('/upgrade/version');
if (d.code !== 0) return;
document.getElementById('currentVersion').textContent = d.data.data.current;
document.getElementById('latestVersion').textContent = d.data.data.latest;
document.getElementById('releaseNotes').textContent = d.data.data.release_notes;
if (d.data.data.has_update) {
document.getElementById('versionStatus').innerHTML = '✨ 有新版本可用';
} else {
document.getElementById('versionStatus').innerHTML = '✅ 已是最新版本';
}
renderUpgradeBackupList(d.backups);
}
function renderUpgradeBackupList(backups) {
const container = document.getElementById('backupList');
if (!backups || backups.length === 0) {
container.innerHTML = '
暂无备份
';
return;
}
container.innerHTML = backups.map(b =>
'
' + b.name + '
' + b.mtime + ' · ' + b.size + '
'
).join('');
}
function handleUpgradeFile(input) {
const file = input.files[0];
if (!file) return;
if (!file.name.endsWith('.zip')) { alert('只支持 zip 格式'); return; }
const formData = new FormData();
formData.append('file', file);
fetch('/api/upgrade/upload', { method: 'POST', body: formData, credentials: 'same-origin' })
.then(r => r.json())
.then(d => {
if (d.code === 0) {
document.getElementById('uploadedFileName').textContent = file.name + ' (' + (file.size/1024).toFixed(1) + ' KB)';
document.getElementById('uploadDropZone').style.display = 'none';
document.getElementById('uploadedPackage').style.display = 'block';
} else { alert(d.msg); }
})
.catch(e => alert('上传失败: ' + e.message));
}
function cancelUpload() {
document.getElementById('upgradeFileInput').value = '';
document.getElementById('uploadDropZone').style.display = 'block';
document.getElementById('uploadedPackage').style.display = 'none';
}
async function runUpgrade() {
if (!confirm('确定开始升级?升级过程中请勿关闭页面!')) return;
document.getElementById('upgradeAlert').className = 'alert show';
document.getElementById('upgradeAlert').textContent = '⏳ 正在升级...';
document.getElementById('upgradeAlert').style.display = 'block';
const d = await api('/upgrade/run', { method: 'POST' });
if (d.code === 0) {
document.getElementById('upgradeAlert').className = 'alert show success';
document.getElementById('upgradeAlert').textContent = '✅ ' + d.msg + ' 页面即将刷新...';
setTimeout(() => window.location.reload(), 3000);
} else {
document.getElementById('upgradeAlert').className = 'alert show error';
document.getElementById('upgradeAlert').textContent = '❌ ' + d.msg;
}
}
async function rollbackTo(backupFile) {
if (!confirm('确定回滚到此版本?')) return;
document.getElementById('upgradeAlert').textContent = '⏳ 正在回滚...';
document.getElementById('upgradeAlert').style.display = 'block';
const d = await api('/upgrade/rollback', {
method: 'POST',
body: JSON.stringify({ backup_file: backupFile })
});
if (d.code === 0) {
document.getElementById('upgradeAlert').className = 'alert show success';
document.getElementById('upgradeAlert').textContent = '✅ ' + d.msg;
setTimeout(() => window.location.reload(), 3000);
} else {
document.getElementById('upgradeAlert').className = 'alert show error';
document.getElementById('upgradeAlert').textContent = '❌ ' + d.msg;
}
}
// =====================
// Production / 生产增强功能
// =====================
async function loadProduction() {
const fw = await api('/firewall/status');
if (fw.code === 0) {
const status = fw.data;
document.getElementById('fwStatus').innerHTML = '
防火墙类型:' + (status.type || '未检测到') + ' | 状态:' + (status.enabled ? '已启用' : '未启用') + '
';
document.getElementById('fwControls').style.display = 'block';
if (status.enabled) {
document.getElementById('fwEnableBtn').style.display = 'none';
document.getElementById('fwEnabledBadge').style.display = 'inline-block';
if (status.rules && status.rules.length > 0) {
let html = '
已开放端口:';
status.rules.forEach(r => {
html += '- ' + r.port + ' (' + r.action + ') - ' + r.from + '
';
});
html += '
';
document.getElementById('fwRulesList').innerHTML = html;
}
} else {
document.getElementById('fwEnableBtn').style.display = 'inline-block';
document.getElementById('fwEnabledBadge').style.display = 'none';
}
} else {
document.getElementById('fwStatus').innerHTML = '
防火墙状态加载失败: ' + (fw.msg || '') + '
';
}
const port = await api('/panel/port');
if (port.code === 0) {
document.getElementById('curPanelPort').value = port.data.port;
}
await loadBackupSettings();
await loadBackupList();
}
async function enableFirewall() {
if (!confirm('确定启用防火墙?将自动开放 22/80/443/8888 端口。')) return;
const d = await api('/firewall/enable', { method: 'POST' });
alert(d.msg);
loadProduction();
}
async function openPort() {
const port = document.getElementById('fwPort').value.trim();
const proto = document.getElementById('fwProto').value;
if (!port) { alert('请输入端口号'); return; }
const d = await api('/firewall/port', {
method: 'POST',
body: JSON.stringify({ port: port, proto: proto, action: 'open' })
});
alert(d.msg);
if (d.code === 0) {
document.getElementById('fwPort').value = '';
loadProduction();
}
}
async function closePort(port) {
if (!confirm('确定关闭端口 ' + port + '?')) return;
const d = await api('/firewall/port', {
method: 'POST',
body: JSON.stringify({ port: port, proto: 'tcp', action: 'close' })
});
alert(d.msg);
loadProduction();
}
async function changePanelPort() {
const newPort = document.getElementById('newPanelPort').value.trim();
if (!newPort) { alert('请输入新端口'); return; }
if (!confirm('确定将面板端口修改为 ' + newPort + '?修改后需要使用新端口重新访问!')) return;
const d = await api('/panel/port', {
method: 'POST',
body: JSON.stringify({ port: newPort })
});
alert(d.msg);
if (d.code === 0) {
setTimeout(() => {
window.location.href = window.location.protocol + '//' + window.location.hostname + ':' + newPort;
}, 2000);
}
}
async function loadBackupSettings() {
const d = await api('/backup/settings');
if (d.code === 0) {
const s = d.data;
document.getElementById('backupEnabled').value = s.enabled ? '1' : '0';
document.getElementById('backupSchedule').value = s.schedule || 'daily';
document.getElementById('backupKeepDays').value = s.keep_days || 7;
document.getElementById('backupDir').value = s.backup_dir || '/backup';
}
}
async function saveBackupSettings() {
const enabled = document.getElementById('backupEnabled').value === '1';
const schedule = document.getElementById('backupSchedule').value;
const keepDays = document.getElementById('backupKeepDays').value;
const backupDir = document.getElementById('backupDir').value.trim();
const d = await api('/backup/settings', {
method: 'POST',
body: JSON.stringify({ enabled: enabled, schedule: schedule, keep_days: keepDays, backup_dir: backupDir })
});
alert(d.msg);
loadBackupSettings();
}
async function runBackupNow() {
if (!confirm('确定立即执行一次备份?')) return;
const d = await api('/backup/run', { method: 'POST' });
alert(d.msg);
setTimeout(loadBackupList, 3000);
}
async function loadBackupList() {
const d = await api('/backup/list');
if (d.code === 0) {
const data = d.data;
let html = '
备份目录:' + data.backup_dir + ' | 总大小:' + data.total_size + '
';
html += '
📁 站点备份
';
if (data.sites.length === 0) {
html += '
暂无备份
';
} else {
data.sites.forEach(f => {
html += '
' + f.name + ' (' + f.size + ')
';
});
}
html += '
';
html += '
🗄️ 数据库备份
';
if (data.databases.length === 0) {
html += '
暂无备份
';
} else {
data.databases.forEach(f => {
html += '
' + f.name + ' (' + f.size + ')
';
});
}
html += '
';
document.getElementById('backupList').innerHTML = html;
}
}
async function deleteBackup(type, filename) {
if (!confirm('确定删除备份 ' + filename + '?')) return;
const d = await api('/backup/delete', {
method: 'POST',
body: JSON.stringify({ type: type, filename: filename })
});
alert(d.msg);
loadBackupList();
}
checkAuth();