基于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
相关推荐
❀͜͡傀儡师2 小时前
docker部署orion-ops一站式智能运维管理平台
运维·docker·容器·orion-ops
闻道且行之2 小时前
Ubuntu 20.04 下 NVIDIA Tesla P40 驱动安装指南(核显桌面 + 计算卡分离方案)
linux·运维·ubuntu·nvidia·p40
oMcLin2 小时前
Ubuntu 24.04 使用 systemd 时 Nginx 服务无法启动的原因分析与解决
linux·nginx·ubuntu
大布布将军2 小时前
☁️ 自动化交付:CI/CD 流程与云端部署
运维·前端·程序人生·ci/cd·职场和发展·node.js·自动化
RisunJan2 小时前
Linux命令-htpasswd命令(创建和管理用于 HTTP 基本认证(Basic Authentication)的密码文件)
linux·运维·http
oMcLin2 小时前
Ubuntu 22.04 配置 Apache 反向代理时无法访问后端应用:Nginx 与 Apache 配置冲突排查
nginx·ubuntu·apache
再睡一夏就好3 小时前
LInux线程池实战:单例模式设计与多线程安全解析
linux·运维·服务器·开发语言·javascript·c++·ecmascript
zfj3213 小时前
Linux第一个用户空间进程init进程的演进过程
linux·运维·网络