首页
统计
友链
留言
导航
微语
关于
更多
直播
壁纸
视频
Search
1
十周年下载
65 阅读
2
go程序在后台运行
6 阅读
3
欢迎使用 Typecho
5 阅读
4
45 个常用Linux 命令,让你轻松玩转Linux!
3 阅读
5
Linux安装Docker完整教程
3 阅读
Linux
php
问道手游
主机
软件
Search
标签搜索
Linux常用命令
Linux安装Docker
php
内网穿透
mysql
问道下载
狗道下载
曼威
累计撰写
13
篇文章
累计收到
0
条评论
今日撰写
0
篇文章
首页
栏目
Linux
php
问道手游
主机
软件
页面
统计
友链
留言
导航
微语
关于
直播
壁纸
视频
搜索到
13
篇与
admin
的结果
2026-08-08
申请lego证书
🔐 证书服务器自动续期 & 日志清理全记录适用环境:hi3798mv100(ARM 32 位,ARMv7l) 证书域名:*.manv.cn + manv.cn 签发机构:Let's Encrypt(通过 lego + 腾讯云 DNS-01 验证) 最后更新:2026-08-09一、前置准备:SSH 免密登录目标:让证书服务器 e.manv.cn 能 免密码 登录博客服务器 y.manv.cn,方便后续自动同步证书。① 在证书服务器 e.manv.cn 上生成 SSH 密钥ssh-keygen -t ed25519 # 一路回车即可,默认生成 ~/.ssh/id_ed25519 和 id_ed25519.pub② 把公钥拷贝到博客服务器 y.manv.cn# 在 e.manv.cn 上执行 ssh-copy-id root@<y.manv.cn的真实IPv4>③ 测试免密是否生效ssh root@<y.manv.cn的真实IPv4>✅ 不用输密码直接登录 = 配置成功二、安装 lego(注意 ARM 架构别下错)hi3798mv100 是 ARM 32 位,需要下载 lego_linux_armv6 那个包(armv6 通吃 armv7l):# 下载(请替换为实际最新版本号) wget https://github.com/go-acme/lego/releases/download/v4.xx.x/lego_v4.xx.x_linux_armv6.tar.gz # 解压 tar xzf lego_v4.xx.x_linux_armv6.tar.gz # 放到系统路径 cp lego /usr/local/bin/ # 验证 lego --version⚠️ 常见坑:下成 arm64 或 amd64 会在运行时报 Exec format error,务必确认是 armv6。三、首次签发证书3.1 设置腾讯云 API 密钥export TENCENTCLOUD_SECRET_ID=<你的腾讯云SecretId> export TENCENTCLOUD_SECRET_KEY=<你的腾讯云SecretKey>3.2 执行签发lego --email 5567374@qq.com --dns tencentcloud \ -d '*.manv.cn' -d 'manv.cn' run💡 为什么要加 -d manv.cn? 单纯 *.manv.cn 管不了根域 manv.cn 本身。加上这一条,根域 + 泛域名会签进 同一张证书,一张证书全搞定。3.3 签发完成后证书位置./.lego/certificates/ ├── _.manv.cn.crt # 证书(含完整链) ├── _.manv.cn.key # 私钥 └── manv.cn.json # 账户/订单信息证书路径取决于你当时 --path 参数,没指定就在当前目录的 .lego/ 下。四、配置 Nginx 使用证书server { listen 443 ssl; server_name manv.cn *.manv.cn; ssl_certificate /etc/nginx/ssl/manv.cn/fullchain.crt; # 即 _.manv.cn.crt ssl_certificate_key /etc/nginx/ssl/manv.cn/manv.cn.key; # 推荐补充的安全配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; }五、自动续期(重点!别忘了这步)Let's Encrypt 证书 90 天过期,lego 自带 renew 命令,配合 crontab 即可实现全自动续期,无需重跑 run。5.1 续期命令lego --email 5567374@qq.com --dns tencentcloud \ -d '*.manv.cn' -d 'manv.cn' \ renew --days 30 --reuse-key--days 30:距过期不足 30 天才执行续期;--reuse-key:复用旧私钥,减少风险。5.2 写成一键脚本(推荐)文件:/opt/lego/renew-manv.sh#!/bin/bash # ============================================================ # manv.cn 证书自动续期脚本 # ============================================================ export TENCENTCLOUD_SECRET_ID=<你的腾讯云SecretId> export TENCENTCLOUD_SECRET_KEY=<你的腾讯云SecretKey> LEGO=/usr/local/bin/lego CERT_DIR=/opt/lego/.lego/certificates NGINX_CERT=/etc/nginx/ssl/manv.cn # 执行续期 $LEGO --email 5567374@qq.com --dns tencentcloud \ -d '*.manv.cn' -d 'manv.cn' \ renew --days 30 --reuse-key # 续期成功才覆盖旧证书 + reload nginx if [ $? -eq 0 ]; then cp "$CERT_DIR/_.manv.cn.crt" "$NGINX_CERT/fullchain.crt" cp "$CERT_DIR/_.manv.cn.key" "$NGINX_CERT/manv.cn.key" nginx -s reload echo "[$(date)] 证书续期成功,nginx 已 reload" else echo "[$(date)] 证书续期失败,请检查日志" fi赋执行权限:chmod +x /opt/lego/renew-manv.sh5.3 加入 crontabcrontab -e添加以下行:0 2 * * * /opt/lego/renew-manv.sh >> /var/log/lego-renew.log 2>&1效果:每天凌晨 2 点检查一次 → 距过期 >30 天就啥也不干 → <30 天自动续签 + 拷证书 + reload nginx。六、清理日志(可选)如果证书目录或日志文件膨胀,可定期清理:# 清理 lego 旧日志(保留最近 7 天) find /var/log/lego* -type f -mtime +7 -delete # 清理 .lego 下的临时文件 find /opt/lego/.lego -type f -name "*.tmp" -delete📋 速查清单步骤关键命令状态① SSH 免密ssh-copy-id root@y.manv.cn⬜② 安装 legocp lego /usr/local/bin/⬜③ 首次签发lego ... run⬜④ Nginx 配置ssl_certificate ...⬜⑤ 续期脚本/opt/lego/renew-manv.sh⬜⑥ Crontab0 2 * * * ...⬜🔒 安全提醒:脚本里的 TENCENTCLOUD_SECRET_KEY 是敏感信息,建议将脚本权限设为 chmod 700,避免被其他用户读取。
2026年08月08日
3 阅读
0 评论
0 点赞
2026-08-08
内网穿透
# 把本地的 8080 端口,通过家里服务器,映射到路由器的内网管理地址ssh -L 8080:192.168.1.1:80 root@y.manv.cn -p 22http://127.0.0.1:8080/
2026年08月08日
2 阅读
0 评论
0 点赞
2026-08-07
PHP 大文件上传、断点续传完整实现思路
PHP 大文件上传 + 断点续传|完整实现思路传统 move_uploaded_file 一把梭只能应付小文件。真上了 GB 级视频 / 安装包 / 日志归档,必须上 分片 + 断点续传。本文给一套可落地的纯 PHP 实现。一、为什么必须做断点续传?假设上传一个 2GB 视频,传统方式的坑:痛点表现后果网络中断传到 80% WiFi 断了从头再来,前功尽弃超时限制max_execution_time 默认 30s大文件必超时内存/大小限制upload_max_filesize 默认 2M直接被拒体验差进度条卡死、不能暂停用户流失断点续传核心价值✅ 失败恢复:从中断处继续,不重头传✅ 分片并行:吃满带宽✅ 可暂停 / 继续✅ 哈希校验:保证文件完整性二、整体架构客户端 服务端 ┌─────────────────┐ ┌─────────────────────┐ │ 文件分片 │ ── 分片1 ──▶ │ 临时目录存分片 │ │ 计算 MD5 指纹 │ ── 分片2 ──▶ │ 记录上传状态 │ │ 本地记录进度 │ ── 分片3 ──▶ │ 合并 + 校验 │ │ 断点恢复 │ ◀─ 响应 ─── │ 返回已传分片列表 │ └─────────────────┘ └─────────────────────┘三条主线:分片化 · 哈希标识 · 状态追踪。三、前端实现3.1 HTML 结构<!DOCTYPE html> <html> <head> <title>断点续传上传</title> <style> .progress-bar { width: 300px; height: 24px; background: #eee; border-radius: 12px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #4CAF50, #45a049); transition: width 0.3s; } .chunk-status { margin-top: 10px; font-size: 13px; color: #666; } </style> </head> <body> <input type="file" id="fileInput" /> <button onclick="startUpload()">开始上传</button> <button onclick="pauseUpload()">暂停</button> <div class="progress-bar"> <div class="progress-fill" id="progressFill" style="width: 0%"></div> </div> <div class="chunk-status" id="status"></div> <script src="uploader.js"></script> </body> </html>3.2 核心上传类(uploader.js)class ChunkUploader { constructor(file, chunkSize = 1024 * 1024) { this.file = file; this.chunkSize = chunkSize; // 每片 1MB this.chunks = Math.ceil(file.size / chunkSize); this.uploadedChunks = new Set(); this.isPaused = false; this.fileHash = ''; this.abortController = null; } // 1. 计算文件哈希(Web Worker 中做,不卡 UI) async calculateHash() { return new Promise((resolve, reject) => { const worker = new Worker('hash-worker.js'); worker.postMessage({ file: this.file }); worker.onmessage = (e) => { if (e.data.type === 'complete') { this.fileHash = e.data.hash; resolve(this.fileHash); } }; worker.onerror = reject; }); } // 2. 询问服务端已传分片 async checkUploadStatus() { const res = await fetch('/check-upload', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file_hash: this.fileHash, file_name: this.file.name, total_size: this.file.size }) }); const data = await res.json(); if (data.status === 'completed') return { needUpload: false, url: data.file_url }; this.uploadedChunks = new Set(data.uploaded_chunks || []); return { needUpload: true }; } // 3. 上传单分片 async uploadChunk(index) { const start = index * this.chunkSize; const end = Math.min(start + this.chunkSize, this.file.size); const blob = this.file.slice(start, end); const fd = new FormData(); fd.append('chunk', blob); fd.append('index', index); fd.append('total_chunks', this.chunks); fd.append('file_hash', this.fileHash); fd.append('file_name', this.file.name); const res = await fetch('/upload-chunk', { method: 'POST', body: fd, signal: this.abortController?.signal }); if (!res.ok) throw new Error(`分片 ${index} 失败`); this.uploadedChunks.add(index); this.updateProgress(); } // 4. 主控流程 async startUpload() { this.isPaused = false; this.abortController = new AbortController(); await this.calculateHash(); const status = await this.checkUploadStatus(); if (!status.needUpload) return alert('文件已存在: ' + status.url); for (let i = 0; i < this.chunks; i++) { if (this.isPaused) break; if (this.uploadedChunks.has(i)) continue; await this.uploadChunk(i); } if (!this.isPaused) await this.mergeFile(); } async mergeFile() { const res = await fetch('/merge-chunks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file_hash: this.fileHash, file_name: this.file.name, total_chunks: this.chunks }) }); const r = await res.json(); if (r.success) alert('上传完成:' + r.url); } pauseUpload() { this.isPaused = true; this.abortController?.abort(); } updateProgress() { const percent = (this.uploadedChunks.size / this.chunks) * 100; document.getElementById('progressFill').style.width = percent + '%'; document.getElementById('status').textContent = `已上传 ${this.uploadedChunks.size}/${this.chunks} 分片`; } } async function startUpload() { const f = document.getElementById('fileInput').files[0]; if (!f) return alert('请选择文件'); window.uploader = new ChunkUploader(f, 2 * 1024 * 1024); // 2MB 分片 await window.uploader.startUpload(); } function pauseUpload() { window.uploader?.pauseUpload(); }3.3 Web Worker 算 MD5(hash-worker.js)self.importScripts('https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.min.js'); self.onmessage = function (e) { const file = e.data.file; const chunkSize = 2 * 1024 * 1024; const chunks = Math.ceil(file.size / chunkSize); let current = 0; const spark = new SparkMD5.ArrayBuffer(); const reader = new FileReader(); reader.onload = function (ev) { spark.append(ev.target.result); if (++current < chunks) loadNext(); else self.postMessage({ type: 'complete', hash: spark.end() }); }; function loadNext() { const s = current * chunkSize; reader.readAsArrayBuffer(file.slice(s, Math.min(s + chunkSize, file.size))); } loadNext(); };{hint|关键点:哈希放 Worker 里算,2GB 文件也不会冻住主线程}四、后端(PHP)4.1 目录结构project/ ├── uploads/ │ ├── chunks/{file_hash}/0.part, 1.part ... │ └── 最终文件 ├── config.php ├── check_status.php ├── upload_chunk.php └── merge_chunks.php4.2 配置 config.php<?php define('UPLOAD_DIR', __DIR__ . '/uploads/'); define('CHUNK_DIR', UPLOAD_DIR . 'chunks/'); define('MAX_FILE_SIZE', 10 * 1024 * 1024 * 1024); define('ALLOWED_EXTENSIONS', ['mp4', 'avi', 'zip', 'pdf', 'docx']); define('CHUNK_EXPIRE_HOURS', 48); is_dir(UPLOAD_DIR) || mkdir(UPLOAD_DIR, 0755, true); is_dir(CHUNK_DIR) || mkdir(CHUNK_DIR, 0755, true);4.3 检查已传状态 check_status.php<?php require_once 'config.php'; header('Content-Type: application/json'); $data = json_decode(file_get_contents('php://input'), true); $hash = $data['file_hash'] ?? ''; $name = $data['file_name'] ?? ''; if (!$hash || !$name) http_response_code(400), exit(json_encode(['error' => '参数缺失'])); $final = UPLOAD_DIR . $name; if (file_exists($final)) { exit(json_encode(['status' => 'completed', 'file_url' => '/uploads/' . $name])); } $dir = CHUNK_DIR . $hash . '/'; $uploaded = []; if (is_dir($dir)) { foreach (scandir($dir) as $f) { if (preg_match('/^(\d+)\.part$/', $f, $m)) $uploaded[] = (int)$m[1]; } sort($uploaded); } echo json_encode(['status' => 'in_progress', 'uploaded_chunks' => $uploaded]);4.4 接收分片 upload_chunk.php<?php require_once 'config.php'; header('Content-Type: application/json'); foreach (['index','total_chunks','file_hash','file_name'] as $k) { if (!isset($_POST[$k])) http_response_code(400), exit(json_encode(['error' => "缺 {$k}"])); } $idx = (int)$_POST['index']; $total = (int)$_POST['total_chunks']; $hash = $_POST['file_hash']; $name = basename($_POST['file_name']); // 防路径穿越 $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); if (!in_array($ext, ALLOWED_EXTENSIONS)) http_response_code(403), exit(json_encode(['error' => '类型不允许'])); if (!isset($_FILES['chunk']) || $_FILES['chunk']['error'] !== UPLOAD_ERR_OK) http_response_code(400), exit(json_encode(['error' => '分片接收失败'])); $dir = CHUNK_DIR . $hash . '/'; is_dir($dir) || mkdir($dir, 0755, true); $path = $dir . $idx . '.part'; if (!move_uploaded_file($_FILES['chunk']['tmp_name'], $path)) http_response_code(500), exit(json_encode(['error' => '保存失败'])); echo json_encode(['success' => true, 'index' => $idx, 'size' => filesize($path)]);4.5 合并分片 merge_chunks.php(流式,不爆内存)<?php require_once 'config.php'; header('Content-Type: application/json'); $d = json_decode(file_get_contents('php://input'), true); $hash = $d['file_hash'] ?? ''; $name = basename($d['file_name'] ?? ''); $total = (int)($d['total_chunks'] ?? 0); if (!$hash || !$name || !$total) http_response_code(400), exit(json_encode(['error' => '参数缺失'])); $dir = CHUNK_DIR . $hash . '/'; for ($i = 0; $i < $total; $i++) { if (!file_exists($dir . $i . '.part')) http_response_code(400), exit(json_encode(['error' => "缺分片 {$i}", 'missing_index' => $i])); } $final = fopen(UPLOAD_DIR . $name, 'wb'); for ($i = 0; $i < $total; $i++) { $part = fopen($dir . $i . '.part', 'rb'); while (!feof($part)) fwrite($final, fread($part, 8192)); fclose($part); unlink($dir . $i . '.part'); } fclose($final); rmdir($dir); echo json_encode(['success' => true, 'file_url' => '/uploads/' . $name, 'size' => filesize(UPLOAD_DIR . $name)]);4.6 统一入口 index.php<?php match ($_GET['action'] ?? '') { 'check' => require 'check_status.php', 'upload' => require 'upload_chunk.php', 'merge' => require 'merge_chunks.php', default => http_response_code(404), };五、高级优化5.1 前端并发上传(并发度 5)把 startUpload 里的串行 for 换成:async uploadAllChunks(concurrency = 5) { const queue = []; for (let i = 0; i < this.chunks; i++) if (!this.uploadedChunks.has(i)) queue.push(() => this.uploadChunk(i)); const exec = new Set(); for (const task of queue) { if (this.isPaused) break; const p = task().then(() => exec.delete(p)); exec.add(p); if (exec.size >= concurrency) await Promise.race(exec); } }5.2 服务端限速 / 防滥用(Redis 频率 + 磁盘检查)$ip = $_SERVER['REMOTE_ADDR']; $cnt = $redis->incr("upload_rate:$ip"); $redis->expire("upload_rate:$ip", 60); if ($cnt > 600) http_response_code(429), exit(json_encode(['error' => '请求过快'])); if (disk_free_space(UPLOAD_DIR) < 500 * 1024 * 1024) http_response_code(507), exit(json_encode(['error' => '磁盘不足']));5.3 定时清理孤儿分片(cron 调 cleanup.php)<?php require 'config.php'; $expire = time() - CHUNK_EXPIRE_HOURS * 3600; foreach (glob(CHUNK_DIR . '*', GLOB_ONLYDIR) as $dir) { if (filemtime($dir) < $expire) { array_map('unlink', glob($dir . '/*')); rmdir($dir); } } echo 'cleanup ok ', date('Y-m-d H:i:s');六、安全清单大文件入口是攻击面,下面几条必须做。风险防护路径遍历basename() 过滤文件名覆盖已有文件按 file_hash 隔离分片目录磁盘被打满disk_free_space() 前置检查分片灌水单 IP 频率限制(Redis)文件类型伪造服务端校验文件头魔数合并并发冲突flock() 加锁合并区七、小结{note|这套方案的特点}🧩 可靠:任意中断可恢复,不丢数据⚡ 高效:分片并行,吃满带宽📈 可扩展:TB 级也能跑🪶 零依赖:纯 PHP + 原生 JS,无额外组件适用:视频平台上传、网盘同步、企业归档、日志批量导入。核心就三件事:把大文件拆小、用哈希做身份、用状态表做记忆。附:完整项目文件清单index.html(前端页面)将第三章 3.1 的 HTML 结构保存为 index.html 即可。uploader.js(前端核心逻辑)将第三章 3.2 的 JavaScript 代码保存为 uploader.js。hash-worker.js(Web Worker 哈希计算)将第三章 3.3 的代码保存为 hash-worker.js。config.php(PHP 配置)将第四章 4.2 的代码保存为 config.php。check_status.php(检查上传状态)将第四章 4.3 的代码保存为 check_status.php。upload_chunk.php(接收分片)将第四章 4.4 的代码保存为 upload_chunk.php。merge_chunks.php(合并分片)将第四章 4.5 的代码保存为 merge_chunks.php。index.php(统一入口路由)将第四章 4.6 的代码保存为 index.php。cleanup.php(定时清理)将第五章 5.3 的代码保存为 cleanup.php。💡 部署提示:将所有 .php 文件放在同一目录,确保 uploads/ 目录可写,配置 cron 定时执行 cleanup.php 即可。
2026年08月07日
2 阅读
0 评论
0 点赞
2026-08-07
LINUX系统优化
🐧 Linux 系统优化 —— 企业生产场景实战指南一、企业生产场景中 Linux 系统的分区方案💡 合理的分区方案是服务器稳定运行的基石。不同业务角色对应不同的分区策略,以下提供三种经过生产验证的方案。📌 方案 1:网站集群节点服务器(数据非关键型)适用场景:集群架构中的某个节点,数据有多份副本,单台故障不影响业务。分区大小建议说明/boot100 ~ 200 MB引导分区,存放内核与启动文件swap物理内存 × 1.5内存 ≥ 8GB 时,配置 8 ~ 16GB 即可/剩余全部空间系统 + 业务 + 数据共用一个分区⚠️ 此方案相当于 Windows 只有一块 C 盘,所有数据混在一起,不适合存放重要数据。📌 方案 2:数据库及存储服务器(数据关键型)⭐ 推荐适用场景:承载数据库(MySQL / PostgreSQL 等)或存储服务(NFS / Ceph 等),数据极其重要。分区大小建议说明/boot100 ~ 200 MB引导分区/50 ~ 200 GB仅存放系统文件,不放业务数据swap物理内存 × 1.5内存 ≥ 8GB 时,配置 8 ~ 16GB 即可/data剩余全部空间存放数据库文件、业务数据等✅ 核心思想:将重要数据单独分区,便于备份、迁移和灾难恢复。/data 名称可替换为 /db、/storage 等。📌 方案 3:大型门户企业服务器(灵活型)适用场景:业务线多、需求不确定,需要按需分配磁盘资源的大型企业。分区大小建议说明/boot100 MB引导分区swap物理内存 × 1.5内存 ≥ 8GB 时,配置 8 ~ 16GB 即可/50 ~ 200 GB仅存放系统文件🔓 剩余磁盘空间不分区,留给各业务部门按需自行分配,灵活性最高。二、内核版本查看与解读🔹 查看内核版本uname -r🔹 内核版本号解读以 3.10.0-1160.45.1.el7.x86_64 为例:字段含义示例值主版本号结构性变化时才更改3次版本号新增功能时变化,偶数=稳定版,奇数=测试版10修订号对次版本的修订/补丁次数0编译次数每次编译可对少数程序优化或修改1160.45.1特殊标识版本特殊信息el7 = Enterprise Linux 7架构系统位数x86_64 = 64 位常见后缀含义:后缀含义elEnterprise Linux(企业版)pp测试版(Pre-Release)fcFedora Corerc候选版本(Release Candidate)三、配置 yum 源仓库💡 yum 源决定了软件下载的速度和稳定性,生产环境强烈推荐使用国内镜像源。🚀 阿里云 yum 源# 方式一:wget 下载 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo # 方式二:curl 下载 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo🚀 清华大学 yum 源# 配置清华源(自动替换官方地址) sudo sed -e 's|^mirrorlist=|#mirrorlist=|g' \ -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \ -i.bak \ /etc/yum.repos.d/CentOS-*.repo📖 详细说明:https://mirrors.tuna.tsinghua.edu.cn/help/centos/✍️ 自定义 yum 源格式cat > /etc/yum.repos.d/local.repo << 'EOF' [app1] name=Local Repository baseurl=http://your-server/path/to/repo gpgcheck=0 enabled=1 EOF🔄 刷新 yum 缓存yum clean all # 清除旧缓存 yum makecache fast # 重建缓存(fast 加速) yum update # 升级所有包(谨慎操作,见下方说明)⚠️ yum update 警告:新装系统可以执行 yum update -y 打全量补丁已上线生产服务器不要轻易执行全量更新,可能导致业务异常遇到特定漏洞(如 2014 年 OpenSSL 心脏出血、Bash 漏洞),仅单独升级对应软件包即可四、系统安装类型与软件包选择✅ 安装原则:最小化安装🎯 不需要的或不确定是否需要的一律不装,最大程度减少攻击面。# 安装基础组件组 yum groupinstall "Compatibility libraries" "Base" "Development tools" yum groupinstall "debugging Tools" "Dial-up Networking Support" # 查看已安装/可用的软件组 yum grouplist📦 安装常用工具包# 必备运维工具 yum install tree telnet dos2unix sysstat lrzsz nc nmap -y # 安装 yum-priorities 源优先级工具 yum install yum-priorities -y📌 yum-priorities 作用:当系统存在多个 yum 源(官方源 + epel + 第三方源)且包含同名软件时,按优先级决定使用哪个源的版本。开启优先级功能:vim /etc/yum/pluginconf.d/priorities.conf确保文件内容如下:[main] enabled=1五、系统服务优化🔻 关闭不需要的服务ntsysv生产环境必须保留的服务(其余一律关闭):服务名作用是否必须crond定时任务调度✅ 必须network网络服务,不开启则无法联网✅ 必须sshdSSH 远程登录守护进程✅ 必须rsyslog系统日志服务(CentOS 5.x 为 syslog)✅ 必须六、关闭不需要的 TTY 控制台💡 默认 Linux 打开 6 个虚拟控制台(ALT+F1 ~ ALT+F6),全部驻留内存。生产服务器通常只需 1~2 个。查看当前 TTY 进程:ps aux | grep tty | grep -v 'grep'修改配置,只保留 2 个控制台:# 1. 编辑 /etc/init/start-ttys.conf vim /etc/init/start-ttys.conf # 修改此行: env ACTIVE_CONSOLES=/dev/tty[1-2] # 2. 编辑 /etc/sysconfig/init vim /etc/sysconfig/init # 修改此行: ACTIVE_CONSOLES=/dev/tty[1-2]七、TCP/IP 网络参数调优🛡️ 增强 SYN Flood 防护能力# 开启 SYN Cookies 防护 echo 'net.ipv4.tcp_syncookies = 1' >> /etc/sysctl.conf # 立即生效 sysctl -p📌 SYN Cookies 是一种防御 SYN Flood 攻击的机制,在高并发 Web 服务器上强烈建议开启。八、优化 Shell 历史记录📝 减少 history 记录条数# 编辑 /etc/profile vim /etc/profile # 将 HISTSIZE=1000 改为: HISTSIZE=100立即生效(无需重启):source /etc/profile💡 减少历史记录条数可以降低敏感信息(如密码、密钥)泄露风险,也节省磁盘空间。九、定时校正服务器时间⏰ 时间同步对分布式系统、数据库主从复制、日志排查至关重要。# 安装 NTP 工具 yum install ntp -y # 添加定时任务 crontab -e加入以下内容(每分钟同步一次阿里云 NTP 服务器):*/1 * * * * /usr/sbin/ntpdate ntp1.aliyun.com &>>/dev/null📌 常用 NTP 服务器:ntp1.aliyun.com、ntp2.aliyun.com、pool.ntp.org十、调整 Linux 最大文件打开数⚠️ 生产环境经常遇到 Too many open files 错误,默认 1024 远远不够。第一步:修改系统级限制编辑 /etc/security/limits.conf,在文件末尾添加:* soft nofile 65535 * hard nofile 65535第二步:开机自动生效编辑 /etc/rc.local,添加:ulimit -SHn 65535验证某进程的实际限制#!/bin/bash for pid in $(ps aux | grep nginx | grep -v grep | awk '{print $2}') do echo "PID: $pid" cat /proc/${pid}/limits | grep 'Max open files' done💡 将脚本保存为 check_fd.sh,chmod +x 后执行即可查看各 worker 进程的文件描述符上限。十一、网卡配置与启动编辑 /etc/sysconfig/network-scripts/ifcfg-eth0:DEVICE=eth0 BOOTPROTO=static HWADDR=00:14:22:1B:71:20 IPV6INIT=no IPV6_AUTOCONF=yes ONBOOT=yes # ✅ 必须为 yes,系统引导时自动启动网卡 NETMASK=255.255.255.192 IPADDR=203.93.236.146 GATEWAY=203.93.236.129 TYPE=Ethernet PEERDNS=yes # 允许 DHCP 获得的 DNS 覆盖本地配置 DNSUSERCTL=no # 不允许普通用户修改网卡配置⚠️ 关键项:ONBOOT=yes 忘记改的话,重启后网卡不启动,服务器直接失联!十二、关闭写磁盘 I/O 功能(减少磁盘压力)📖 Linux 文件的三个时间属性时间属性含义atime文件访问时间mtime文件内容修改时间ctime文件 inode 变更时间(权限、属主等)💡 对于存放大量小文件的分区(如 Web 图片目录),记录 atime 会产生大量不必要的写 I/O。禁用 atime 更新编辑 /etc/fstab,在对应分区挂载选项中添加 noatime,nodiratime:/dev/sda5 /data/photos ext3 defaults,noatime,nodiratime 0 0✅ 修改后执行 mount -o remount /data/photos 或重启生效。十三、创建具有 sudo 权限的用户推荐方式:使用 visudo(自带语法检查)visudo在 root ALL=(ALL) ALL 下方添加:# 需要输入密码的 sudo 权限 lilutong ALL=(ALL) ALL # 免密码 sudo(自动化运维场景常用) lilutong ALL=(ALL) NOPASSWD:ALL✅ visudo 会在保存时自动校验语法,避免因配置错误导致所有 sudo 失效。十四、SSH 登录安全加固 ⭐ 必做# 1. 禁止 root 远程登录 sed -i 's@#PermitRootLogin yes@PermitRootLogin no@' /etc/ssh/sshd_config # 2. 禁止空密码登录 sed -i 's@#PermitEmptyPasswords no@PermitEmptyPasswords no@' /etc/ssh/sshd_config # 3. 关闭 SSH 反向 DNS 查询(加快登录速度) sed -i 's@#UseDNS yes@UseDNS no@' /etc/ssh/sshd_config # 重启 sshd 使配置生效 systemctl restart sshd安全加固效果:加固项防御目标禁止 root 远程登录防止暴力破解 root 密码禁止空密码登录防止弱口令/无口令账户关闭 UseDNS消除登录卡顿,减少 DNS 超时风险⚠️ 操作前务必确认:至少有一個具有 sudo 权限的普通用户可以正常登录,否则改完配置可能无法管理服务器!📋 优化项速查总表序号优化项关键命令/配置重要程度1分区方案规划/boot + / + /data + swap⭐⭐⭐2内核版本检查uname -r⭐⭐3配置国内 yum 源阿里云 / 清华源⭐⭐⭐4最小化安装 + 基础包yum groupinstall⭐⭐⭐5关闭无用服务仅保留 crond/network/sshd/rsyslog⭐⭐⭐6减少 TTY 控制台保留 1~2 个⭐⭐7SYN Flood 防护net.ipv4.tcp_syncookies=1⭐⭐⭐8缩减 history 记录HISTSIZE=100⭐⭐9NTP 时间同步ntpdate ntp1.aliyun.com⭐⭐⭐10调大文件打开数nofile 65535⭐⭐⭐11网卡 ONBOOT=yes/etc/sysconfig/network-scripts/⭐⭐⭐12关闭 atime 写盘noatime,nodiratime⭐⭐13创建 sudo 用户visudo⭐⭐⭐14SSH 安全加固禁 root / 禁空密码 / 关 DNS⭐⭐⭐🎯 总结:以上 14 项优化覆盖了磁盘分区、内核调优、软件源、服务管理、网络安全等核心维度,是经过大量生产环境验证的 Linux 系统初始化标准动作。建议将其编写为自动化脚本(Ansible / Shell),在新服务器上线时一键执行,既高效又避免遗漏。📝 本文由原文改写美化,原文作者:李MAX,来源:稀土掘金
2026年08月07日
1 阅读
0 评论
0 点赞
2026-08-07
Linux安装Docker完整教程
🐳 Docker 在 Linux 下的部署与实战指南💡 背景最近接手了几个项目,发现项目的部署基本都基于 Docker。幸亏早在几年前就已经熟悉了 Docker 的基础用法,整个过程并未抓瞎。随着云原生生态的蓬勃发展,Docker 的重要性愈发凸显。本文将带你一步步完成 Linux 环境下 Docker 的部署与配置。建议收藏,以备不时之需;如果你对 Docker 感兴趣,也可以直接照着步骤动手实践,早日享受容器化带来的便利与魅力。一、Docker 及系统版本要求Docker 从 17.03 版本开始分为两个分支:版本类型说明CE(Community Edition)社区版,免费,推荐学习和生产使用EE(Enterprise Edition)企业版,强调安全合规,需付费📌 本文基于 Docker CE 社区版✅ 系统要求64 位版本的 CentOS 7 / 8 或更高版本Linux 内核版本 ≥ 3.10二、查看系统与内核版本2.1 查看 Linux 发行版本方式一:lsb_release -alsb_release -a输出示例:LSB Version: :core-4.1-amd64:core-4.1-noarch Distributor ID: CentOS Description: CentOS Linux release 7.6.1810 (Core) Release: 7.6.1810 Codename: Core方式二:cat /etc/redhat-releasecat /etc/redhat-releaseCentOS Linux release 7.6.1810 (Core)✅ 当前系统为 CentOS 7.6,满足 Docker 要求2.2 查看 Linux 内核版本方式一:uname -r(推荐)uname -r3.10.0-1160.45.1.el7.x86_64方式二:cat /proc/versioncat /proc/version方式三:uname -auname -a✅ 当前内核版本 3.10.0,满足 Docker ≥ 3.10 的要求三、Docker 自动化安装(推荐 ✅)Docker 官方与国内镜像站都提供了一键安装脚本,适合快速部署。3.1 官方一键安装(阿里云镜像加速)curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun3.2 国内 DaoCloud 一键安装curl -sSL https://get.daocloud.io/docker | sh⏳ 执行完成后,Docker 即安装完毕,无需手动干预💡 两条命令任选其一即可四、Docker 手动安装(进阶 · 可控性更强)手动安装流程分为三步:① 卸载旧版本 → ② 设置仓库 → ③ 安装 Docker4.1 卸载旧版本(可选)如果系统中曾安装过旧版本 Docker,建议先清理:yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine \ docker-ce4.2 设置 YUM 仓库安装依赖工具sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2添加 Docker 仓库官方源(较慢):sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo✅ 国内镜像源(推荐):镜像源仓库地址阿里云http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo清华大学https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo使用阿里云镜像源:sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo4.3 安装 Docker安装最新版 Docker CE(推荐)sudo yum install -y docker-ce docker-ce-cli containerd.io仅安装 Docker CE(无 CLI)yum install -y docker-ce📌 安装完成后,Docker 默认 未启动,需手动启动五、Docker 启动与验证5.1 启动 Docker 服务sudo systemctl start docker5.2 验证 Docker 是否正常工作拉取 hello-world 镜像:sudo docker pull hello-world运行 hello-world 容器:sudo docker run hello-world成功输出示例:Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image. 4. The Docker daemon streamed that output to the Docker client.🎉 至此,Docker 安装与启动全部完成!5.3 Docker 服务管理命令操作命令守护进程重载systemctl daemon-reload启动 Dockersystemctl start docker重启 Dockersystemctl restart docker关闭 Dockersystemctl stop docker查看状态systemctl status docker开机自启systemctl enable docker六、卸载 Docker(清理环境)6.1 移除安装包yum remove docker-ce6.2 删除镜像、容器与配置数据rm -rf /var/lib/docker⚠️ 此操作不可逆,会删除所有镜像、容器、卷和网络数据七、Docker 常用操作命令速查表 ⚡7.1 镜像操作操作命令🔍 搜索镜像docker search 镜像名⬇️ 拉取镜像docker pull 镜像名📋 查看镜像docker images🗑️ 删除镜像docker rmi 镜像ID7.2 容器操作操作命令📋 查看运行中的容器docker ps📋 查看所有容器docker ps -a▶️ 启动已停止的容器docker start 容器ID⏹️ 停止容器docker stop 容器ID🔄 重启容器docker restart 容器ID🗑️ 删除容器docker rm 容器ID7.3 运行与进入容器操作命令说明🚀 新建并启动容器docker run -it ubuntu /bin/bash交互式终端🔗 进入容器(推荐)docker exec -it 容器ID /bin/bash不中断容器🔗 附加到容器docker attach 容器ID退出会停止容器💡 推荐使用 docker exec 进入容器,退出时不会停止容器运行7.4 其他实用命令# 查看 Docker 帮助 docker help # 查看 Docker 版本 docker version # 查看 Docker 系统信息 docker info # 查看容器日志 docker logs 容器ID # 查看容器资源占用 docker stats🎨 Joe 主题美化说明美化元素效果🐳 Emoji 图标章节标题一目了然📊 表格版本对比、镜像源、命令速查整齐排列📝 引用块 >背景说明与注意事项高亮🔤 代码块统一使用 bash,语法高亮清晰➖ 分割线模块之间视觉分隔加粗重点关键路径、推荐操作突出显示📖 收藏本文,下次部署 Docker 直接照做即可!如果觉得有帮助,欢迎分享给更多小伙伴 🚀
2026年08月07日
3 阅读
0 评论
0 点赞
1
2
3