昨晚访问 USTC 的 Rust Crates 反代源一直不太顺畅,于是有了自己搭建的想法。早上上课摸鱼弄了出来。搭建方案写篇博客,看到网上相关的教程还挺少的...

目前在自己的站点上已经提供公共反向代理 crates.io 的服务,欢迎使用:

反代 crates.io:https://crates.delbertbeta.cc/
Cargo registry:https://crates.delbertbeta.cc/crates.io-index (2h 同步一次)

使用方法

使用文本编辑器打开下面这个文件,如果没有则自行创建。

// Linux & Mac:
~/.cargo/config

// Windows:
C:\Users\${your-username}\.cargo\config

编辑文本内容如下:

[source.crates-io]
replace-with = 'delbertbeta'

[source.delbertbeta]
registry = "https://crates.delbertbeta.cc/crates.io-index"

重新在项目中运行 cargo build 即可从新的源更新 index。

反向代理 crates.io

因为 crates.io 不是一个单纯静态文件分发站点,不同于 Linux 软件源那样使用 rsync 之类的工具同步所有的文件到服务器上,保持同步文件结构,单纯的静态分发就可以了,crates.io 是依靠 api 对外服务的,例如:https://crates.delbertbeta.cc/api/v1/crates,crates.io 项目中没有给出手动部署的方案,官方推荐使用 Heroku 一键部署,但是部署到国外的云平台上,带宽速度可连接性和 S3 一样又不能得到保障。明显此时直接反向代理 crates.io 是省时省力又节约自己服务器流量和硬盘的好办法,这里给出 nginx 反向代理 crates.io 的方案。

首先在 /etc/nginx/sites-enabled 下复制或创建一个虚拟站点配置文件。

其核心部分如下:

location / {
    proxy_buffering on;
    proxy_connect_timeout 10s;
    proxy_cache STATIC;
    proxy_cache_valid 200 12h;
    proxy_cache_valid 400 502 504 1m;
    proxy_cache_valid any 5m;
    proxy_cache_revalidate on;
    proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
    proxy_set_header Host crates.io;
    proxy_ssl_server_name on;
    proxy_pass https://crates.io;
}

这里我们用到了 nginx 的 cache feature,用硬盘空间换降低流量开销和提高速度,还需要配置一下 cache。

# File: /etc/nginx/nginx.conf
http {
    ...
    proxy_cache_path ${path-to-your-cache-folder} keys_zone=STATIC:100m levels=1:2 inactive=6h max_size=1g;
    ...
}

注意将 ${path-to-your-cache-folder} 替换成你的缓存要存放的目录。

配置完成之后保存,systemctl restart nginx,在浏览器里面访问这个站点就可以看到代理成功的 crates.io 了。

搭建 crates.io-index

有了反代的 crates.io,可是 cargo 并不会去从我们的站点去下载 crate,所以还需要自己搭建一个 crates.io-index service。

crates.io 是把自己所有的包的索引放在 Github 上的,其实我们平时用的 Cargo 的时候它自动去拉取索引其实就是在本地克隆一份这个仓库:https://github.com/rust-lang/crates.io-index/

我们在服务器上也拉取一份这个仓库

git clone https://github.com/rust-lang/crates.io-index.git
cd crates.io-index

这个仓库下有一个 config.json,打开编辑,嘿嘿嘿,很明白你要做什么了吧。

# File: crates.io-index/config.json
{
  "dl": "https://crates.delbertbeta.cc/api/v1/crates",
  "api": "https://crates.delbertbeta.cc"
}

然后 git add . && git commit 素质二连。

这时候,为了方便好用,我们选择部署一个 Git over HTTP 服务来将这个仓库暴露出去,作为 Cargo 的 source registry。

这里直接使用 git-core 自带的 git-http-backend 配合 fcgiwrap 来构建一个 cgi,提供 Git over HTTP 服务。

apt install fcgiwrap
systemctl start fcgiwrap

修改站点配置文件

location ~ /crates.io-index/(.*) {
     fastcgi_pass  unix:/var/run/fcgiwrap.socket;
     include       fastcgi_params;
     fastcgi_param SCRIPT_FILENAME    /usr/lib/git-core/git-http-backend;
     # export all repositories under GIT_PROJECT_ROOT
     fastcgi_param GIT_HTTP_EXPORT_ALL "";
     fastcgi_param GIT_PROJECT_ROOT    ${parent-folder-of-your-repo};
     fastcgi_param PATH_INFO           /crates.io-index/$1;
     fastcgi_param   REMOTE_USER     $remote_user;
}

注意将上面的 ${parent-folder-of-your-repo} 替换成你的 crates.io-index 仓库的父文件夹的路径

然后重启 nginx 即可。

配置 SSL (可选)

我这里直接用 LetsEncrypt

sudo apt-get install certbot python-certbot-nginx -t stretch-backports
certbot

选择你的域名,全自动配置。

定时同步

建立 crates.io-index.sh

#!/bin/sh

cd ${path-of-crates-io-index}
git fetch
git rebase origin/master

exit 0

使用 cron 定时任务定时执行以上脚本,执行 crontab -e

# 每两小时同步一次
0 */2 * * * sh ${path-to-the-file}/crates.io-index.sh

完成

可以按照文章最开始的配置方法,将自己本机的 Cargo 配置成自己搭建的 Crates 源了。快乐~