基于nginx服务文件上传及下载

文章目录

    • [1. 安装依赖和下载nginx](#1. 安装依赖和下载nginx)
    • [2. 编译安装nginx](#2. 编译安装nginx)
    • [3. 创建简单的nginx配置文件](#3. 创建简单的nginx配置文件)
    • [4. 创建必要的目录和文件](#4. 创建必要的目录和文件)
    • [5. 启动脚本](#5. 启动脚本)
    • [6. 启动nginx服务](#6. 启动nginx服务)
    • [7. 测试文件服务](#7. 测试文件服务)
    • [8. 系统优化脚本](#8. 系统优化脚本)
    • [9. 常见问题解决](#9. 常见问题解决)

准备一台 redhat8/CentOS7的系统部署一个简单的nginx文件服务器。请按照以下步骤操作:

1. 安装依赖和下载nginx

bash 复制代码
# 安装编译依赖
yum install -y gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel

# 创建nginx用户
useradd -s /sbin/nologin nginx

# 下载nginx 1.16.1
cd  /usr/local/src
wget http://nginx.org/download/nginx-1.16.1.tar.gz
tar -zxvf nginx-1.16.1.tar.gz
cd nginx-1.16.1

2. 编译安装nginx

bash 复制代码
# 配置编译参数
./configure --prefix=/usr/local/nginx \
            --with-http_ssl_module \
            --with-http_stub_status_module \
            --with-http_gzip_static_module \
            --with-http_dav_module

# 编译并安装
make && make install

这些模块作用

模块 生产环境必要性 用途
http_ssl_module ⚠️ 必须 HTTPS 安全通信
http_stub_status_module 强烈推荐 监控 Nginx 性能
http_gzip_static_module 推荐 优化静态资源加载
http_dav_module ⚠️ 按需 文件管理/WebDAV 集成

3. 创建简单的nginx配置文件

编辑 /usr/local/nginx/conf/nginx.conf

nginx 复制代码
user  nginx;
worker_processes  1;

# 添加这一行,指定打开文件数量限制
worker_rlimit_nofile 65535;  # 这个值应该等于或大于worker_connections

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;

    # 增加超时时间,大文件上传需要更长时间
    keepalive_timeout  300;
    client_body_timeout 300;
    client_header_timeout 300;
    send_timeout 300;

    # 设置client_max_body_size为2G,支持大文件上传
    client_max_body_size 2g;

    # 临时文件目录,确保nginx有权限写入
    client_body_temp_path /tmp/nginx_temp;

    # 增加缓冲区大小
    client_body_buffer_size 128k;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;

    server {
        listen       80;
        server_name  localhost;

        # 统一的文件存储目录,同时支持上传(PUT)和下载(GET)
        location /files {
            alias   /data/files/;

            # 允许目录浏览
            autoindex on;
            autoindex_exact_size off;
            autoindex_localtime on;
            charset utf-8;

            # 允许PUT方法上传
            dav_methods PUT;
            create_full_put_path on;

            # 允许的HTTP方法
            limit_except GET PUT OPTIONS {
                deny all;
            }

            # 处理OPTIONS预检请求
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'Content-Type';
                return 204;
            }

            # 添加CORS头
            if ($request_method = PUT) {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'Content-Type';
            }

            # 上传文件大小限制(覆盖全局设置)
            client_max_body_size 2g;
        }

        # 根目录,提供简单的上传页面
        location / {
            root   /usr/local/nginx/html;
            index  upload.html;
        }
    }
}

4. 创建必要的目录和文件

bash 复制代码
# 创建存储目录
mkdir -p /data/files
mkdir -p /usr/local/nginx/html

# 设置权限
chmod -R 755 /data
chown -R nginx:nginx /data
bash 复制代码
# 创建简单的上传页面
cat > /usr/local/nginx/html/upload.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>简单文件上传下载</title>
    <meta charset="utf-8">
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, sans-serif; background: #f5f5f5; padding: 20px; }
        .container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #333; margin-bottom: 20px; text-align: center; }
        h2 { color: #666; margin: 20px 0 10px; }
        .upload-area { border: 2px dashed #ccc; border-radius: 5px; padding: 40px; text-align: center; margin: 20px 0; transition: border-color 0.3s; }
        .upload-area.dragover { border-color: #4CAF50; background: #f9fff9; }
        .file-input-container { margin: 20px 0; }
        .upload-btn, .browse-btn {
            background: #4CAF50; color: white; border: none; padding: 12px 24px;
            border-radius: 4px; cursor: pointer; font-size: 16px; margin: 5px;
        }
        .browse-btn { background: #2196F3; }
        .cancel-btn { background: #f44336; }
        .upload-btn:hover { background: #45a049; }
        .browse-btn:hover { background: #0b7dda; }
        .cancel-btn:hover { background: #d32f2f; }
        .upload-btn:disabled { background: #ccc; cursor: not-allowed; }
        #fileInput { display: none; }
        .file-info {
            margin: 15px 0; padding: 15px; background: #f9f9f9;
            border-radius: 4px; border-left: 4px solid #4CAF50;
        }
        .file-name { font-weight: bold; color: #333; }
        .file-size { color: #666; margin-left: 10px; }
        .file-remove { color: #f44336; cursor: pointer; margin-left: 15px; }
        .file-remove:hover { text-decoration: underline; }
        .file-list { margin-top: 20px; }
        .file-item { padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; }
        .file-item-name { flex-grow: 1; }
        .file-item-size { color: #666; margin: 0 15px; }
        .file-actions a { color: #4CAF50; text-decoration: none; margin-left: 10px; }
        .file-actions a:hover { text-decoration: underline; }
        .status { margin-top: 15px; padding: 10px; border-radius: 4px; display: none; }
        .success { background: #dff0d8; color: #3c763d; display: block; }
        .error { background: #f2dede; color: #a94442; display: block; }
        .info { background: #d9edf7; color: #31708f; display: block; }
        .progress { width: 100%; height: 20px; background: #f0f0f0; border-radius: 10px; margin: 10px 0; overflow: hidden; }
        .progress-bar { height: 100%; background: #4CAF50; width: 0%; transition: width 0.3s; }
        .selected-file { display: flex; align-items: center; justify-content: space-between; padding: 10px; background: #e8f5e8; border-radius: 4px; margin: 10px 0; }
    </style>
</head>
<body>
    <div class="container">
        <h1>简单文件上传下载服务</h1>

        <div class="upload-area" id="dropArea">
            <p>拖放文件到此处,或</p>
            <div class="file-input-container">
                <input type="file" id="fileInput">
                <button class="browse-btn" onclick="document.getElementById('fileInput').click()">选择文件</button>
            </div>
            <p>支持大文件上传,最大2G</p>
        </div>

        <!-- 选择的文件信息区域 -->
        <div id="selectedFileInfo" style="display: none;">
            <div class="selected-file">
                <div>
                    <strong>已选择文件:</strong>
                    <span id="selectedFileName"></span>
                    <span id="selectedFileSize" class="file-size"></span>
                </div>
                <button class="cancel-btn" onclick="clearSelectedFile()">取消选择</button>
            </div>
        </div>

        <button class="upload-btn" id="uploadBtn" onclick="uploadFile()" disabled>上传文件</button>

        <div class="progress" id="progressContainer" style="display: none;">
            <div class="progress-bar" id="progressBar"></div>
        </div>

        <div id="status"></div>

        <h2>文件列表 (<a href="/files" target="_blank">浏览目录</a>)</h2>
        <div class="file-list" id="fileList">
            <p id="loadingMsg">正在加载文件列表...</p>
        </div>
    </div>

    <script>
    // 页面加载完成后获取文件列表
    window.onload = function() {
        loadFileList();

        // 拖放功能
        var dropArea = document.getElementById('dropArea');
        var fileInput = document.getElementById('fileInput');

        dropArea.addEventListener('dragover', function(e) {
            e.preventDefault();
            dropArea.classList.add('dragover');
        });

        dropArea.addEventListener('dragleave', function() {
            dropArea.classList.remove('dragover');
        });

        dropArea.addEventListener('drop', function(e) {
            e.preventDefault();
            dropArea.classList.remove('dragover');
            fileInput.files = e.dataTransfer.files;
            handleFileSelect();
        });

        fileInput.addEventListener('change', handleFileSelect);
    };

    function handleFileSelect() {
        var fileInput = document.getElementById('fileInput');
        var uploadBtn = document.getElementById('uploadBtn');
        var selectedFileInfo = document.getElementById('selectedFileInfo');

        if (fileInput.files.length > 0) {
            var file = fileInput.files[0];

            // 显示选择的文件信息
            document.getElementById('selectedFileName').textContent = file.name;
            document.getElementById('selectedFileSize').textContent = '(' + formatFileSize(file.size) + ')';
            selectedFileInfo.style.display = 'block';

            // 启用上传按钮
            uploadBtn.disabled = false;
        } else {
            // 隐藏文件信息
            selectedFileInfo.style.display = 'none';
            uploadBtn.disabled = true;
        }
    }

    function clearSelectedFile() {
        var fileInput = document.getElementById('fileInput');
        var uploadBtn = document.getElementById('uploadBtn');
        var selectedFileInfo = document.getElementById('selectedFileInfo');

        // 清空文件选择
        fileInput.value = '';

        // 隐藏文件信息
        selectedFileInfo.style.display = 'none';

        // 禁用上传按钮
        uploadBtn.disabled = true;

        // 清空状态信息
        document.getElementById('status').innerHTML = '';
        document.getElementById('status').className = 'status';
    }

    function uploadFile() {
        var fileInput = document.getElementById('fileInput');
        var file = fileInput.files[0];

        if (!file) {
            showStatus('请先选择文件', 'error');
            return;
        }

        // 禁用上传按钮,防止重复点击
        var uploadBtn = document.getElementById('uploadBtn');
        uploadBtn.disabled = true;
        uploadBtn.textContent = '上传中...';

        // 显示进度条
        document.getElementById('progressContainer').style.display = 'block';
        document.getElementById('progressBar').style.width = '0%';

        var xhr = new XMLHttpRequest();

        // 使用PUT方法上传到/files目录
        xhr.open('PUT', '/files/' + encodeURIComponent(file.name), true);

        xhr.onload = function() {
            document.getElementById('progressContainer').style.display = 'none';

            if (xhr.status === 201 || xhr.status === 200 || xhr.status === 204) {
                showStatus('上传成功!文件:' + file.name + ' (' + formatFileSize(file.size) + ')', 'success');

                // 清空文件选择
                fileInput.value = '';

                // 清空选择的文件信息
                document.getElementById('selectedFileInfo').style.display = 'none';

                // 恢复上传按钮
                uploadBtn.textContent = '上传文件';

                loadFileList(); // 刷新文件列表
            } else {
                showStatus('上传失败:' + xhr.status + ' ' + xhr.statusText, 'error');
                uploadBtn.disabled = false;
                uploadBtn.textContent = '上传文件';
            }
        };

        xhr.onerror = function() {
            document.getElementById('progressContainer').style.display = 'none';
            showStatus('上传出错,请检查网络连接', 'error');
            uploadBtn.disabled = false;
            uploadBtn.textContent = '上传文件';
        };

        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
                var percent = Math.round((e.loaded / e.total) * 100);
                document.getElementById('progressBar').style.width = percent + '%';
                uploadBtn.textContent = '上传中 ' + percent + '%';
            }
        };

        xhr.send(file);
    }

    function loadFileList() {
        fetch('/files/')
            .then(response => response.text())
            .then(html => {
                // 解析HTML获取文件列表
                var parser = new DOMParser();
                var doc = parser.parseFromString(html, 'text/html');
                var links = doc.querySelectorAll('a');
                var files = [];

                links.forEach(link => {
                    var href = link.getAttribute('href');
                    var text = link.textContent;
                    // 跳过父目录链接和无效链接
                    if (href !== '../' && !href.startsWith('?') && text && !text.includes('Parent Directory')) {
                        files.push({
                            name: decodeURIComponent(text),
                            url: '/files/' + encodeURIComponent(text),
                            size: link.nextSibling ? link.nextSibling.textContent.trim() : ''
                        });
                    }
                });

                displayFileList(files);
            })
            .catch(error => {
                document.getElementById('loadingMsg').textContent = '加载文件列表失败';
                console.error('加载文件列表失败:', error);
            });
    }

    function displayFileList(files) {
        var fileList = document.getElementById('fileList');

        if (files.length === 0) {
            fileList.innerHTML = '<p>暂无文件</p>';
            return;
        }

        var html = '';
        files.forEach(file => {
            html += `
                <div class="file-item">
                    <span class="file-item-name">${file.name}</span>
                    <span class="file-item-size">${file.size}</span>
                    <div class="file-actions">
                        <a href="${file.url}" download>下载</a>
                        <a href="${file.url}" target="_blank">查看</a>
                    </div>
                </div>
            `;
        });

        fileList.innerHTML = html;
    }

    function showStatus(message, type) {
        var statusDiv = document.getElementById('status');
        statusDiv.innerHTML = message;
        statusDiv.className = 'status ' + type;
    }

    function formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes';
        var k = 1024;
        var sizes = ['Bytes', 'KB', 'MB', 'GB'];
        var i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }

    // 每30秒刷新一次文件列表
    setInterval(loadFileList, 30000);
    </script>
</body>
</html>
EOF

5. 启动脚本

bash 复制代码
# 创建systemd服务文件
cat > /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

[Install]
WantedBy=multi-user.target
EOF

6. 启动nginx服务

bash 复制代码
# 重新加载systemd
systemctl daemon-reload

# 启动nginx
systemctl start nginx

# 设置开机启动
systemctl enable nginx

# 检查状态
systemctl status nginx

7. 测试文件服务

上传文件(使用curl):

bash 复制代码
# 启动nginx
/usr/local/nginx/sbin/nginx

# 测试配置文件
/usr/local/nginx/sbin/nginx -t

# 查看nginx进程
ps aux | grep nginx

# 测试curl上传
echo "测试文件内容" > test-upload.txt
curl -X PUT -T test-upload.txt http://localhost/files/test-upload.txt

# 测试curl下载
curl http://localhost/files/test-upload.txt

# 测试目录浏览
curl http://localhost/files/

# 查看文件是否在正确位置
ls -la /data/files/

使用web页面上传:

访问 http://192.168.100.140 或者 http://192.168.100.140/upload.html

  • 后续找个时间优化下,使用账号及密码登录,才能上传及下载文件。

8. 系统优化脚本

  • 可选
bash 复制代码
#!/bin/bash

# nginx优化配置脚本

echo "优化nginx配置..."

# 调整系统参数
cat >> /etc/sysctl.conf << EOF
# nginx优化参数
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_tw_buckets = 5000
EOF

# 应用系统参数
sysctl -p

# 调整文件描述符限制
cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
nginx soft nofile 65535
nginx hard nofile 65535
EOF

echo "优化完成,请重新登录使文件描述符限制生效"

9. 常见问题解决

如果遇到权限问题:

bash 复制代码
# 修改nginx运行用户
chown -R nginx:nginx /usr/local/nginx

# 重新加载配置
/usr/local/nginx/sbin/nginx -s reload

如果无法上传大文件:

bash 复制代码
# 编辑nginx.conf,调整client_max_body_size
vim /usr/local/nginx/conf/nginx.conf

# 编辑upload.html, 修改WEB 页面显示 <p>支持大文件上传,最大2G</p>
vim  /usr/local/nginx/html/upload.html

# 修改后重启nginx
systemctl restart nginx
相关推荐
用户0328472220707 小时前
如何搭建本地yum源(上)
运维
ping某1 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工3 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智3 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_3 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉3 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造
AC赳赳老秦3 天前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw