给鸡蛋再找个篮子——使用Gitea搭建轻量级Git服务器

前言

由于我之前提到过,想要用树莓派自己搭建一个Git的服务,于是我就去找了一下各种Git的服务端,最后就发现了这个使用go开发的Git服务端——Gitea。

Gitea的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用Go作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了x86,amd64,还包括 ARM 和 PowerPC。

因为是用Go开发,Gitea的主要程序就是一个原生的二进制可执行文件,而且Gitea可以使用SQLite当做数据库,这样它的资源占用比Gitlab这种Java开发需要虚拟机的要少的多,甚至他在官网上就写着用树莓派就能运行,这不是巧了吗。

  • 最低的系统硬件要求为一个廉价的树莓派
  • 如果用于团队项目,建议使用 2 核 CPU 及 1GB 内存

而且由于是Go开发,所以环境搭建就容易的很多了。

搭建过程

首先先去官网下载平台对应的二进制文件。

https://dl.gitea.io/gitea

直到这篇文章撰写时,最新的版本为1.16.8,而我是准备运行在树莓派上的,他的cpu架构是arm6,所以最后我下载的文件为gitea-1.16.8-linux-arm-6,下载后更名为gitea,然后传入服务器中。

将二进制文件移动到/usr/local/bin/gitea,并使用chmod +x添加运行权限。

这个操作也可以在服务器环境通过下面的命令执行,记得换成你对应平台的文件的地址。

wget -O gitea https://dl.gitea.io/gitea/1.16.8/gitea-1.16.8-linux-arm-6
chmod +x gitea
sudo mv gitea /usr/local/bin/gitea

由于我们搭建的是Git服务器,所以需要提前安装好git,并且git版本要大于20,这里不同的系统可以用不同的包管理器来安装,这里贴出官方给出的不同系统下的安装方式。

Debian/Ubuntu

For the latest stable version for your release of Debian/Ubuntu

# apt-get install git For Ubuntu, this PPA provides the latest stable upstream Git version

# add-apt-repository ppa:git-core/ppa # apt update; apt install git

Fedora

# yum install git (up to Fedora 21)

# dnf install git (Fedora 22 and later)

Gentoo

# emerge --ask --verbose dev-vcs/git

Arch Linux

# pacman -S git

openSUSE

# zypper install git

Mageia

# urpmi git

Nix/NixOS

# nix-env -i git

FreeBSD

# pkg install git

Solaris 9/10/11 (OpenCSW)

# pkgutil -i git

Solaris 11 Express

# pkg install developer/versioning/git

OpenBSD

# pkg_add git

Alpine

$ apk add git

Red Hat Enterprise Linux, Oracle Linux, CentOS, Scientific Linux, et al. RHEL and derivatives typically ship older versions of git. You can download a tarball and build from source, or use a 3rd-party repository such as the IUS Community Project to obtain a more recent version of git.

Slitaz

$ tazpkg get-install git

安装好git之后,可以使用git --version检查一下版本是否大于20。

接下来的操作,官方的中文文档里有缺失,我一开始也踩了坑,然后照着英文版的文档做才成功搭建。

首先创建一个用户Gitea运行的用户,Gitea是不允许使用root用户运行的。

adduser \
   --system \
   --shell /bin/bash \
   --gecos 'Git Version Control' \
   --group \
   --disabled-password \
   --home /home/git \
   git

然后创建需要使用的目录和文件。

mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
touch /etc/gitea/app.ini
chown root:git /etc/gitea/app.ini
chmod 770 /etc/gitea/app.ini

接下来,将服务文件gitea.service复制到/etc/systemd/system/gitea.service,这里如果懒也可以直接复制我下面的精简版(如果需要使用第三方数据库,请自行查看配置文件,并取消对应数据库的注释)。

[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target

[Service]

RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/

ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target

接下来就是设置开机自启和启动服务了。

sudo systemctl enable gitea
sudo systemctl start gitea

然后服务应该就会在3000端口运行了(使用服务运行默认是在3000端口,如果需要修改端口,要在服务配置的命令中加上--install-port 端口号),从浏览器访问IP:3000来打开安装页面。

安装页面有中文,很简单,对着选就行了,我这里数据库选SQLite

在这里可以修改端口,等下安装好之后,重启就是新的端口了。如果SSH端口不填的话就是关闭SSH功能,我的机器因为准备做内网穿透,所以不准备用SSH了,我就关了。

个性化

我们的服务配置里面,把Gitee的资产文件都放在了/var/lib/gitea目录中,这个目录下面有三个子目录customdatalog,分别存放着自定义内容,数据,以及日志。而我们想要做个性化,就需要修改custom里面的文件。

关于custom目录,里面的public目录里的内容,会在服务启动后,被路由到网站的根目录下面。也就是说如果你有一些自定义的图片,样式,脚本什么的,都应该放在这里面。

安装好Gitee服务后,打开主页,我们看到的是默认的样式,虽然Gitee比较简洁,但是也是提供了一些类似主题修改的个性化功能的。

添加主题

首先先说主题的修改,Gitee的主题读取的策略是首先需要你在配置文件里面添加可选择的主题列表,之后再去custom/public/css目录中,读取theme-主题名.css的样式文件。所以如果你下载了新的主题或者自定义了一些CSS样式,那么你需要这样做。

我们假设主题的名字叫做test首先将你的CSS样式重命名为theme-test.css,然后将他放入custom/public/css目录中。

之后打开配置文件/etc/gitea/app.ini,在[ui]字段下面(如果没有请手动添加),修改THEMES字段,加入test主题,如下。

...
[ui]
# 这里gitea是默认主题,arc-green是默认暗黑主题
THEMES = gitea,arc-green,test 
...

保存重启服务之后,在用户登陆后的主题设置里面,就可以看到test的主题可供选择了。

修改默认主题

如果你想要用户在未登录,或者是新用户默认情况下就设置为某个主题,你需要这么做。

首先按照上文所说,将你的主题加入到可选择列表中,例如上文中的test主题。然后修改配置文件的[ui]字段,在下面加入DEFAULT_THEME,值等于你想选择的默认主题,如下。

...
[ui]
THEMES = gitea,arc-green,test
# 这里将默认主题设置为了test
DEFAULT_THEME = test 
...

保存重启服务之后,打开首页就可以看到在未登录的时候,主题设置成了test

修改页面样式

在默认的首页样式中,我们可以看到除了我们的网站名字以外,还有一些默认的文字和图案内容。比如一款极易搭建的自助 Git 服务易安装,跨平台,轻量级,开源化等等。想要修改这些内容,你需要这样做。

首先需要下载Gitea的源代码。

https://dl.gitea.io/gitea/1.16.8/gitea-src-1.16.8.tar.gz

下载完成解压之后,我们可以在里面找到templates,这里面放着的就是全部页面的默认模板。我们可以将这个目录复制到custom目录下,然后修改这里面的模板,这样在服务启动后,Gitea就会优先读取custom目录下我们修改过的模板。当然,实际上你只需要保留你修改过的模板文件在custom目录里就好。

我们这次是要修改首页的内容,我们打开custom/templates/home.tmpl,修改一下里面的内容。

{{template "base/head" .}}
<div class="page-content home">
	<div class="ui stackable middle very relaxed page grid">
		<div class="sixteen wide center aligned centered column">
			<div>
				<img class="logo" width="220" height="220" src="{{AssetUrlPrefix}}/img/logo.svg"/>
			</div>
			<div class="hero">
				<h1 class="ui icon header title">
					{{AppName}}
				</h1>
				<h2>这里就是页面的副标题</h2>
			</div>
		</div>
	</div>
	<!-- 注释掉不想要的内容
    <div class="ui stackable middle very relaxed page grid">
		<div class="eight wide center column">
			<h1 class="hero ui icon header">
				{{svg "octicon-flame"}} {{.i18n.Tr "startpage.install"}}
			</h1>
			<p class="large">
				{{.i18n.Tr "startpage.install_desc" | Str2html}}
			</p>
		</div>
		<div class="eight wide center column">
			<h1 class="hero ui icon header">
				{{svg "octicon-device-desktop"}} {{.i18n.Tr "startpage.platform"}}
			</h1>
			<p class="large">
				{{.i18n.Tr "startpage.platform_desc" | Str2html}}
			</p>
		</div>
	</div>
	<div class="ui stackable middle very relaxed page grid">
		<div class="eight wide center column">
			<h1 class="hero ui icon header">
				{{svg "octicon-rocket"}} {{.i18n.Tr "startpage.lightweight"}}
			</h1>
			<p class="large">
				{{.i18n.Tr "startpage.lightweight_desc" | Str2html}}
			</p>
		</div>
		<div class="eight wide center column">
			<h1 class="hero ui icon header">
				{{svg "octicon-code"}} {{.i18n.Tr "startpage.license"}}
			</h1>
			<p class="large">
				{{.i18n.Tr "startpage.license_desc" | Str2html}}
			</p>
		</div>
	</div>
  -->
</div>
{{template "base/footer" .}}

修改完成后,保存重启,就可以看到页面的样式已经改变啦。

结语

虽然Gitea很多配置还要修改文件+重启服务,可能没有那么方便,但是他较小的资源占用和性能需求,拿来当做个人使用的服务的话还是比较适合的。

前几天Gitee称因为需要审查,迫于无奈下架了大量的开原仓库的事件引发了轩然大波,作为一个普普通通的小开发者,我对这个事件也没有什么评价。我所能做的就是再多搭建一个平台,用来保存我那些“可能也没什么价值”的源码罢了。毕竟都说不要把鸡蛋装在一个篮子里,而现如今最大的篮子就是Github,但是谁又能保证这个篮子不会破呢?

关于Nginx的一些骚操作

前几天给服务器重装了个系统,用来反向代理一些接口,结果学会了几个骚操作,分享给大家。

反向代理使用了多个证书的网站

一上来属于是一个坑,我们都知道同一个IP可以被很多个域名指向,通过不同的域名来访问同一个IP的服务器,则是通过header里的host来判断是访问到哪个站点。但是这里面会有一种情况,就是这个站点是具有tls加密也就是https加密,同时这个站点配置了多个证书,这时候如果你直接代理的话,则会报证书错误,必须在location里添加proxy_ssl_server_name on,例如下面这样。

proxy_set_header Host "www.example.com";
proxy_ssl_server_name on;

这样源站的服务器才能知道你是为了哪一个域名和证书而来,才回给你发放对应的证书。 注:其实这个就是SNI功能,某些网站的访问就是在这一部被屏蔽掉的。

前端跨域时的处理

前端跨域限制是浏览器的一种安全措施,叫做同源策略(Sameoriginpolicy),属于是浏览器的一种很基础的安全策略。在同源策略限制下,网页的JS会不允许访问协议、域名或者端口不同的内容和资源。但是有时候我们前端的代码可能会需要访问不同域名或者端口的接口,所以我们会使用Nginx来处理跨域问题。 一般情况下,我们在网站配置的location下面,增加下面两条,就可以允许服务器被跨域访问了。

add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Headers * always;

但是在做反向代理的时候,如果源站配置过同源限制,则需要再加上下面这两条。

proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Headers;

这两条的意思是丢弃掉源站的同源配置,同时你增加了新的配置,这样才能正确配置。 但是其实还有一个问题,就是浏览器会发送methodoptions的请求,用来判断是否可以接收跨域请求。 那既然我们已经允许了全部的跨域请求,我们就可以给options请求直接返回一个200告诉他可以。

if ($request_method = "OPTIONS") {
	return 200;
}

由此一来我们就可以随便调用这个反向代理的接口了。

反向代理Url使用变量

反向代理时,有可能源网址并不是固定的,而是随着某些nginx的变量改变的,这种时候,就要在proxy_pass中拼接一个变量,像下面这样。

set $name 'tom';
proxy_pass https://www.example.com/$name;

但是如果直接这样使用可能会报错,需要在server字段下,添加dns配置,如下。

resolver 8.8.8.8;

这样才能在proxy_pass中拼接变量。

使用lua获取post请求的body

这是这次学到的最骚的一个操作,一般来说nginx是不能直接获取到post请求中的内容的,但是大家都知道lua是一种非常容易嵌入各种各样环境的语言,nginx中也是有嵌入lua可以使用的,所以我们可以通过lua来获取postbody

首先如果想获取body的话,需要先在server字段中,添加如下配置。

lua_need_request_body on;

这条配置代表了声明lua需要读取requestbody

之后我们在location下,添加如下配置。

set $name '';
rewrite_by_lua_block {
	local post = ngx.req.get_post_args()
	ngx.var.name = post.name
}
proxy_pass https://www.example.com/$name;

首先先使用原生nginx语句,定义一个变量name,之后添加rewrite_by_lua_block代码段,这里因为我是需要在proxy_pass之前处理数据,所以使用了rewrite_by_lua_block,还有其他的节点可以使用,下面再说。 然后内部就是lua语句了,定义一个post变量,赋值为ngx.req.get_post_args()的返回值,这里就获取到了body的数据了,之后ngx.var.name这个变量就等于是之前我们使用set定义的变量name,所以这里就是给变量name赋值post.name,也就是我们请求上送过来的body中的name字段。 最后再把name变量拼接到proxy_pass后面。 于是就实现了,可以通过post请求中的name字段,来修改反向代理的地址了。

扩展内容——关于在nginx中使用lua

nginx提供了几个lua代码的处理阶段,具体如下表。

处理阶段 可用范围
init_by_lua http
set_by_lua server, server if, location, location if
rewrite_by_lua http, server, location, location if
access_by_lua http, server, location, location if
content_by_lua location, location if
header_filter_by_lua http, server, location, location if
body_filter_by_lua http, server, location, location if
log_by_lua http, server, location, location if
timer *

init_by_lua

在nginx重新加载配置文件时,运行里面lua脚本,常用于全局变量的申请。 例如lua_shared_dict共享内存的申请,只有当nginx重起后,共享内存数据才清空,这常用于统计。

set_by_lua

设置一个变量,常用与计算一个逻辑,然后返回结果 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

rewrite_by_lua

在access阶段前运行,主要用于rewrite

access_by_lua

主要用于访问控制,能收集到大部分变量,类似status需要在log阶段才有。 这条指令运行于nginx access阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。

content_by_lua

阶段是所有请求处理阶段中最为重要的一个,运行在这个阶段的配置指令一般都肩负着生成内容(content)并输出HTTP响应。

header_filter_by_lua

一般只用于设置Cookie和Headers等 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

body_filter_by_lua

一般会在一次请求中被调用多次, 因为这是实现基于 HTTP 1.1 chunked 编码的所谓“流式输出”的。 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

log_by_lua

该阶段总是运行在请求结束的时候,用于请求的后续操作,如在共享内存中进行统计数据,如果要高精确的数据统计,应该使用body_filter_by_lua。 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

timer

可参考官方文档:http://wiki.nginx.org/HttpLuaModule

在lua代码中,可以使用ngx.var.变量名获取ngxin的原生变量,例如ngx.var.name等价于nginx中的$name,但是注意的一点是,这个变量必须预先在nginx中声明。

可以在不同的请求阶段后面增加_block,则可以使用代码块形式嵌入lua脚本,如下。

set $name '';
rewrite_by_lua "
	ngx.var.name = 'tom'
"
rewrite_by_lua_block {
	ngx.var.name = "tom"
}
使用Cloudflare Workers反带P站图片

近期一直在搞Pixiv相关的东西,也拿到了Pivision的原作者reiya的正式授权,成了新的维护者。于是一个又一个的问题摆在我面前,我必须要把她们一个一个推倒。 目前比较棘手的问题是:如何注册账号。实际上解决办法也很简单,反带P站就完事了。但这会出现另一个严重的问题:反带了P站,大量的图片会让我的小服务器吃不消。这时候,我发现了Cloudflare Workers。

简介

Cloudflare提供了免费的额度,每天10万次请求而不计算流量,简直就是用来反带的神器!

教程

1. 前提准备

  • 一个域名
  • 域名要使用Cloudflare的NS解析

2. 步骤

首先注册一个Cloudflare账号(估计大多数人都有),之后把你的域名使用Cloudflare解析(这个过程我觉得没必要详细讲了……)

然后打开你的域名管理页面,点击上面的Workers,再点击Launch Editor,进入脚本编辑器。

在编辑器中,点击左侧的Add script,之后输入脚本的名称,随便填一个pximg就好,之后点击Confirm创建脚本。

之后左侧会多出来一个脚本,点进去开始编辑。

删除掉里面所有的代码,粘贴下面的代码进去。

addEventListener("fetch", event => {
  let url = new URL(event.request.url);
  url.hostname = "i.pximg.net";

  let request = new Request(url, event.request);
  event.respondWith(
    fetch(request, {
      headers: {
        'Referer': 'https://www.pixiv.net/'
      }
    })
  );
});

就像这样,然后点击save保存脚本。然后点击左上角的Dashboard返回域名面板。

之后点击Add route,填写https://你的域名/*,并且下面选择刚刚创建的脚本,举例如图。

再之后点击new Workers dashboard,根据提示创建一个二级域名。例如我的二级域名是yojigen.workers.dev,而刚刚创建的脚本的域名就是pximg.yojigen.workers.dev

最后一步,到DNS页面,添加一个CNAME记录到你的脚本域名下,并开启云加速。

至此,你就可以使用你的域名来作为Pixiv的图片反向代理了。

低配VPS上的MySQL优化

如果各位自己搞过网站的人可能会比较熟悉宝塔面板这个东西,装环境简单好用,我这个站也是一直在用其实是因为我太菜不会运维。不过新版的宝塔限制了MySQL不能在内存小于1.5G的机器里安装,而我正好前几天把自己的服务器配置缩到了1G,这就十分难受了。不过后来找了点资料,发现了解决办法。

配置

首先打开/www/server/panel/data/plugin.json这个配置文件,然后通过关键词找到如下代码:

{
    "name": "mysql",
    "versions": [{
            "m_version": "5.5",
            "dependnet": "",
            "version": "62",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 256
        },
        {
            "m_version": "5.6",
            "dependnet": "",
            "version": "45",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 768
        },
        {
            "m_version": "5.7",
            "dependnet": "",
            "version": "27",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 1560
        },
        {
            "m_version": "5.1",
            "dependnet": "",
            "version": "73",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 128
        },
        {
            "m_version": "AliSQL",
            "dependnet": "",
            "version": "5.6.32",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 768
        },
        {
            "m_version": "mariadb_10.0",
            "dependnet": "",
            "version": "38",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 768
        },
        {
            "m_version": "mariadb_10.1",
            "dependnet": "",
            "version": "40",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 1024
        },
        {
            "m_version": "mariadb_10.2",
            "dependnet": "",
            "version": "25",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 1024
        },
        {
            "m_version": "mariadb_10.3",
            "dependnet": "",
            "version": "16",
            "os_limit": 0,
            "cpu_limit": 1,
            "mem_limit": 1500
        },
        {
            "m_version": "8.0",
            "dependnet": "",
            "version": "17",
            "os_limit": 1,
            "cpu_limit": 2,
            "mem_limit": 4096
        }
    ],
    "os": "Linux"
}

然后把你需要安装的版本的mem_limit改成0,保存,就可以去安装了。

优化内存占用

其实宝塔之所以不让小内存机器装MySQL5.7,其实也是因为这玩意内存占用是真的高,启动就占300M,一跑起来随便就五六百。不过咱们的网站需求并不高,所以完全可以降低点配置。 先吧InnoDB关了,这玩意启动就会占好几百,反正MyISAM也是够用的。

default_storage_engine = MyISAM

剩下的就不多说,按下图配,暴力缩减内存占用到350M。连512的小鸡都吃的下。

各位朋友如果装宝塔面板,建议还是装在CentOS上,我发现在Ubuntu上用宝塔,数据库安装总有奇奇怪怪的问题,到CentOS就一路畅通,反正怪得很。