< 返回版块

BlackLuny 发表于 2023-08-21 13:31

私人图床搭建

Github仓库

1、目标:

  • 安全性:使用HTTPS进行加密。
  • 私密性:完全自我管理的存储。
  • 独创性:尽可能自行编写代码。

2、整体方案

上传流程

上传流程

显示流程

显示流程

PC上运行一个图床web服务器,提供上传和下载功能。

3、图床服务器源码

use axum::{
    extract::{Multipart, Path},
    routing::get,
    routing::post,
    Json, Router,
};
use hyper::{Body, Response, StatusCode};
// use multipart::server::Multipart;
use std::{
    net::SocketAddr,
    path::{self},
};
use tokio::fs;
// use tokio_stream::wrappers::BytesStream;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

async fn serve_image(Path(filename): Path<String>) -> Result<Response<Body>, String> {
    if filename.find("..").is_some() || filename.find("/").is_some() {
        return Ok(hyper::Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body(Body::from("Not Found"))
            .unwrap()
            .into());
    }
    if filename.find(".png").is_none() {
        return Ok(hyper::Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body(Body::from("Not Found"))
            .unwrap()
            .into());
    }
    let path = format!("uploads/{}", filename);
    if let Ok(data) = fs::read(&path).await {
        Ok(hyper::Response::new(Body::from(data)))
    } else {
        Ok(hyper::Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body(Body::from("Not Found"))
            .unwrap()
            .into())
    }
}

#[derive(Debug, Deserialize, Serialize)]
struct UploadResp {
    dst: String,
}

#[derive(Debug, Deserialize, Serialize)]
struct UploadReq {
    file: String,
}

async fn upload(data: String) -> Result<Json<UploadResp>, StatusCode> {
    let data: UploadReq = serde_json::from_str(&data).map_err(|_| StatusCode::BAD_REQUEST)?;
    let data = base64::decode(data.file).map_err(|_| StatusCode::BAD_REQUEST)?;
    let base_path = std::path::Path::new("uploads");
    if !base_path.exists() {
        fs::create_dir(base_path).await.unwrap();
    }
    let file_name = format!("{}.png", Uuid::new_v4());
    // let filename = format!("uploads/1.png");
    fs::write(&base_path.join(&file_name), data).await.unwrap();

    Ok(Json(UploadResp {
        dst: format!(
            "https://img.example.com:444/{}", // 主意!!!!这儿修改为你的服务器域名和端口
            base_path.join(&file_name).to_string_lossy()
        ),
    }))
}

#[tokio::main]
async fn main() {
    // std::env::set_var("RUST_LOG", "trace");
    env_logger::init();
    let app = Router::new()
        .route("/upload", post(upload))
        .route("/uploads/:filename", get(serve_image));

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("Listening on http://{}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

/upload:使用POST方法,供upic上传图片。
/uploads:使用GET方法,获取图片数据。

4、部署

4.1 在vps上

设置frp实现内网穿透,

a、下载frp
wget https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_arm64.tar.gz
tar -xvzf ./frp_0.51.3_linux_arm64.tar.gz
b、修改配置文件
vim frps.ini

配置为:

[common]
bind_port = 7000
# 密码,修改为自己的
token = 123456
# https端口
vhost_https_port = 444
c、后台运行frp服务端
nohup ./frps -c frps.ini &

4.2 PC上

a、下载frp
wget https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_arm64.tar.gz
tar -xvzf ./frp_0.51.3_linux_arm64.tar.gz
b、修改客户端配置文件
vim frpc.ini

配置为:

[common]
# vps 公网ip
server_addr = 1.1.1.1 
server_port = 7000
# 密码
token = 123456
# 端口,与服务器保持一致
vhost_https_port = 444

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
 
[test_https2http]
type = https
# 域名
custom_domains = img.example.com
plugin = https2http
# 图床服务器的端口,如果没修改源码,默认不用改
plugin_local_addr = 127.0.0.1:3000
# https证书,自行搜索如何获取https证书
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
c、后台运行frp客户端
nohup ./frpc -c frpc.ini &
d、运行图床http服务器
nohup ./img_server &

4.4 upic设置

添加一个自定义的图床:

upic设置

只需修改域名部分。完成设置后,可以进行验证,如果一切正常,将返回一个URL链接。

更多教程欢迎关注我的博客

评论区

写评论
作者 BlackLuny 2023-08-21 13:38

good,回头试一下

廴壬吉 2023-08-21 13:36

为什么用frp,有更好的 https://github.com/lbl8603/vnt rust写的

1 共 2 条评论, 1 页