前言
部署文件服务器有很多办法,有时候在生产环境需要将服务器文件共享,本篇通过Nginx监听8000端口,部署文件服务器。
一、怎么部署文件服务器
部署文件服务器可以通过以下办法:
- 基于Http协议,开启服务: python3 -m http.server 8000 这是最快的方法,只要在同一网域访问服务器地址和端口号就可以访问文件目录下的文件。
- 使用 vsftpd(FTP 服务器,适合大文件传输)
- 使用 Nginx(高性能 HTTP 服务器)
说明:第一种需要后台启动使用 “nohup python3 -m http.server 8000 &” 清除后台使用 “pkill -f "python3 -m http.server"”
二、基于Nginx部署服务
1. 安装Nginx
sudo apt install nginx
2.配置文件
进入 /etc/nginx/sites-available/fileserver
server {
listen 8000;
server_name files_server;
root /files_server;
# turn on WebDAV
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:r;
client_max_body_size 500M;
# support php
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
client_max_body_size 500M;
}
autoindex on;
}
以上root 目录使用真是的服务器对应的文件根目录文件夹名,对应的最大传输文件大小限制是500M。
3. 启动Nginx服务
启动并开机启动服务
sudo ln -s /etc/nginx/sites-available/fileserver /etc/nginx/sites-enabled/
sudo systemctl restart nginx
sudo systemctl enable nginx
通过浏览器访问 http://192.168.x.xx:8000/访问服务器文件,如果不能访问尝试开启防火墙:
sudo ufw allow 8000/tcp
sudo ufw reload
如果仍然不能访问,尝试更改文件夹权限,如下:
# 替换为你的实际文件夹路径
sudo chown -R www-data:www-data /path/to/your/folder
sudo chmod -R 755 /path/to/your/folder
访问结果如下:
4. 基于PHP上传文件
Nginx 本身不支持直接上传文件,WebDAV 是 HTTP 的扩展协议,支持文件管理(上传/删除等)。安装模块:
sudo apt install nginx-extras # 包含 WebDAV 模块
启动web DAV,如上配置,已经启动:
设置目录权限:
sudo chown -R www-data:www-data /path/to/your/folder
sudo chmod -R 775 /path/to/your/folder
然后通过客户端软件上传,为了更好的体验,使用PHP使用网页上传,安装PHP
sudo apt install php-fpm
修改Nginx配置支持php
重启服务:
sudo systemctl restart nginx php-fpm
注意:对于php服务也有可能是其它版本名,如 systemctl status php8.3-fpm.service
写入前端upload.html和后端upload.php文件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传系统</title>
<style>
body {
font-family: 'Arial', sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.upload-container {
border: 2px dashed #ccc;
padding: 30px;
text-align: center;
border-radius: 8px;
background: #f9f9f9;
margin-bottom: 20px;
}
#file-input {
display: none;
}
.file-label {
display: inline-block;
padding: 10px 20px;
background: #4CAF50;
color: white;
cursor: pointer;
border-radius: 4px;
transition: background 0.3s;
}
.file-label:hover {
background: #45a049;
}
#file-name {
margin-top: 10px;
font-size: 14px;
color: #666;
}
#upload-btn {
padding: 10px 25px;
background: #2196F3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
#upload-btn:hover {
background: #0b7dda;
}
#upload-btn:disabled {
background: #cccccc;
cursor: not-allowed;
}
#progress-container {
margin-top: 20px;
display: none;
}
#progress-bar {
width: 100%;
background: #e0e0e0;
border-radius: 4px;
}
#progress {
height: 20px;
background: #4CAF50;
border-radius: 4px;
width: 0%;
transition: width 0.3s;
}
#result {
margin-top: 20px;
padding: 15px;
border-radius: 4px;
}
.success {
background: #dff0d8;
color: #3c763d;
}
.error {
background: #f2dede;
color: #a94442;
}
</style>
</head>
<body>
<h1>文件上传系统</h1>
<div class="upload-container">
<input type="file" id="file-input" name="file">
<label for="file-input" class="file-label">选择文件</label>
<div id="file-name">未选择文件</div>
</div>
<button id="upload-btn" disabled>开始上传</button>
<div id="progress-container">
<div>上传进度:</div>
<div id="progress-bar">
<div id="progress"></div>
</div>
</div>
<div id="result"></div>
<script>
const fileInput = document.getElementById('file-input');
const fileName = document.getElementById('file-name');
const uploadBtn = document.getElementById('upload-btn');
const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress');
const resultDiv = document.getElementById('result');
// 文件选择处理
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
fileName.textContent = `已选择: ${e.target.files[0].name}`;
uploadBtn.disabled = false;
} else {
fileName.textContent = '未选择文件';
uploadBtn.disabled = true;
}
});
// 上传处理
uploadBtn.addEventListener('click', async () => {
const file = fileInput.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
try {
uploadBtn.disabled = true;
progressContainer.style.display = 'block';
resultDiv.className = '';
resultDiv.innerHTML = '';
const xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true);
// 进度处理
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
progressBar.style.width = percent + '%';
}
};
xhr.onload = () => {
try {
const response = JSON.parse(xhr.responseText);
if (response.status === 'success') {
resultDiv.className = 'success';
resultDiv.innerHTML = `
<strong>上传成功!</strong><br>
文件名: ${response.data.original_name}<br>
保存路径: ${response.data.path}<br>
文件大小: ${(response.data.size / 1024).toFixed(2)} KB
`;
} else {
resultDiv.className = 'error';
resultDiv.innerHTML = `<strong>上传失败:</strong>${response.message}`;
}
} catch (e) {
resultDiv.className = 'error';
resultDiv.innerHTML = `<strong>解析响应失败:</strong>${xhr.responseText}`;
} finally {
uploadBtn.disabled = false;
}
};
xhr.onerror = () => {
resultDiv.className = 'error';
resultDiv.innerHTML = '网络请求失败';
uploadBtn.disabled = false;
};
xhr.send(formData);
} catch (error) {
resultDiv.className = 'error';
resultDiv.innerHTML = `错误: ${error.message}`;
uploadBtn.disabled = false;
}
});
</script>
</body>
</html>
<?php
// 开发环境配置
error_reporting(E_ALL);
ini_set('display_errors', 1);
header('Content-Type: application/json; charset=utf-8');
// ================= 配置区域 =================
$UPLOAD_DIR = __DIR__ . '/uploads/'; // 上传目录(自动创建在脚本同级目录)
$ALLOWED_TYPES = [ // 允许的MIME类型
'text/plain' => 'txt',
'image/jpeg' => 'jpg',
'image/png' => 'png',
'application/pdf' => 'pdf'
];
$MAX_SIZE = 500 * 1024 * 1024; // 500MB
// ================= 上传处理 =================
try {
// 1. 验证请求方法
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
throw new RuntimeException('只接受POST请求');
}
// 2. 检查文件上传状态
if (!isset($_FILES['file']) || !is_uploaded_file($_FILES['file']['tmp_name'])) {
throw new RuntimeException('文件上传失败(可能表单enctype错误)');
}
$file = $_FILES['file'];
// 3. 验证错误代码
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new RuntimeException(match($file['error']) {
UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => '文件超过大小限制',
UPLOAD_ERR_PARTIAL => '文件只有部分被上传',
UPLOAD_ERR_NO_FILE => '未选择上传文件',
default => '上传错误代码: ' . $file['error']
});
}
// 4. 验证文件大小
if ($file['size'] > $MAX_SIZE) {
throw new RuntimeException("文件大小不能超过 " . round($MAX_SIZE/1024/1024) . "MB");
}
// 5. 验证文件类型
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
//if (!array_key_exists($mime, $ALLOWED_TYPES)) {
// throw new RuntimeException("不支持的文件类型: $mime");
//}
// 6. 创建目标目录(如不存在)
if (!file_exists($UPLOAD_DIR) && !mkdir($UPLOAD_DIR, 0755, true)) {
throw new RuntimeException("无法创建上传目录");
}
// 7. 生成安全文件名
// 7. 生成安全文件名(使用原始名称,存在则覆盖)
$filename = basename($file['name']); // 获取原始文件名
$target_path = $UPLOAD_DIR . $filename;
// 如果文件已存在,先删除旧文件(实现覆盖)
if (file_exists($target_path)) {
unlink($target_path);
}
// 8. 核心操作:移动上传文件
if (!move_uploaded_file($file['tmp_name'], $target_path)) {
throw new RuntimeException('文件保存失败: ' . print_r(error_get_last(), true));
}
// 9. 返回成功响应
echo json_encode([
'status' => 'success',
'data' => [
'path' => $target_path,
'size' => $file['size'],
'mime' => $mime,
'original_name' => $file['name'],
'download_url' => 'download.php?file=' . urlencode($filename)
]
], JSON_UNESCAPED_SLASHES);
} catch (Throwable $e) {
http_response_code(400);
echo json_encode([
'status' => 'error',
'message' => $e->getMessage(),
'debug' => [
'php_ini_limit' => ini_get('upload_max_filesize'),
'allowed_types' => array_keys($ALLOWED_TYPES)
]
]);
}
配置 php服务配置文件
vi /etc/php/8.3/fpm/php.ini
更改如下:
upload_max_filesize = 500M ; 允许上传的最大文件大小
post_max_size = 600M ; POST 数据最大大小(必须 ≥ upload_max_filesize)
memory_limit = 1000M ; 内存限制
file_uploads = On ; 启用文件上传
重启服务即可
sudo systemctl restart php-fpm # 或 php8.2-fpm
进入服务器页面,点击upload.html即可进入上传文件页面:
总结
以上就是基于Nginx部署上传文件方式,利于快速实现上传和访问服务器文件。