0%

TLS-SNI-01已经deprecated,但certbot尚不支持tls-alpn-01验证方法,因此可以使用dehydrated或者acme.sh通过https来获取Let’s Encrypt证书。

下面使用acme.sh,由于使用80,443端口的权限,拷贝证书文件的权限以及reload nginx的权限等问题,使用acme.sh正确的姿势应该是使用root账户来运行。

安装

1
2
# curl https://get.acme.sh sh
# source ~/.bashrc # 使acme.sh alias生效

如果使用acme.sh standalone方式来获取证书,还需要安装socat

1
$ sudo apt install socat

http方式获取证书

http验证支持standalone、webroot或webserver(apache,nginx)方式获取证书,获取证书的过程不会破坏系统环境。

standalone方式,acme.sh会启动一个使用80端口的web server

1
# acme.sh --issue -d mydomain.com --standalone

80端口需要特权用户才能监听

webroot方式,指定正在运行的网站的root目录

1
# acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/

webserver方式,指定使用的web server,目前支持apache和nginx

1
2
# acme.sh --issue -d mydomain.com --apache
# acme.sh --issue -d mydomain.com --nginx

默认申请的是RSA证书,acme.sh同样支持申请ECC证书,只要添加额外的--keylength参数即可,支持申请256和384位的ECC证书

1
# acme.sh --issue -d mydomain.com --standalone --keylength ec-256

安装证书

1
2
3
4
# acme.sh --installcert -d mydomain.com \\
--key-file /etc/nginx/ssl/mydomain.com.key \\
--fullchain-file /etc/nginx/ssl/fullchain.cer \\
--reloadcmd "systemctl force-reload nginx"

自动更新证书

acme.sh自动安装了crontab入口,acme.sh会自动记录下申请证书和安装证书的命令,所以会在设定的周期内自动自行这些指令。

手动更新证书

1
# acme.sh --renew -d example.com --force

或者ECC证书

1
# acme.sh --renew -d example.com --force --ecc

acme.sh自动更新

1
# acme.sh --upgrade --auto-upgrade

关闭自动更新

1
# acme.sh --upgrade --auto-upgrade 0

手动更新

1
# acme.sh --upgrade

卸载

1
# acme.sh --uninstall

References:
[1]Deploying Let’s Encrypt certificates using tls-alpn-01 (https)
[2]使用TLS-ALPN-01验证签发证书
[3]dehydrated
[4]acme.sh
[5]TLS ALPN without downtime
[6]acme.sh中文说明

windows平台生成的zip文件名是使用CP936也就是GBK编码的,导致这样的文件在linux平台utf-8环境下解压缩的时候文件名会成为乱码,这个问题由来已久,但并没有从zip那边有个根本性的解决方案。

可以使用python的zipfile模块来解决这个问题。

python3版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3

import os
import sys
import zipfile

print("Processing File " + sys.argv[1])

file=zipfile.ZipFile(sys.argv[1],"r");
for name in file.namelist():
utf8name=name.encode('cp437').decode('cp936')
print("Extracting " + utf8name)
pathname = os.path.dirname(utf8name)
if not os.path.exists(pathname) and pathname!= "":
os.makedirs(pathname)
data = file.read(name)
if not os.path.exists(utf8name):
fo = open(utf8name, "wb")
fo.write(data)
fo.close
file.close()

因为zipfile把所有非utf-8编码格式的文件名都作为cp437进行处理,因此需要先还原回cp437,然后重新编码为cp936。

python版本见Reference[1]。

References:

[1]Linux 下 zip 文件解压乱码解决方案

当配置了多个源,特别是添加backports源之后,一个package可能有多个候选版本
源是有优先级的,apt会默认从优先级高的源安装package

可以通过apt-cache来查看package候选版本信息

1
2
3
4
5
6
7
8
9
$ apt-cache policy tmux
tmux:
Installed: (none)
Candidate: 2.3-4
Version table:
2.8-1~bpo9+1 100
100 http://ftp.tw.debian.org/debian stretch-backports/main amd64 Packages
2.3-4 500
500 http://ftp.tw.debian.org/debian stretch/main amd64 Packages

可以看到backports源优先级比较低,所以默认安装并不会安装最新版本

可以通过指定版本来安装

1
$ sudo apt install tmux=2.8-1~bpo9+1

bpo就是backports的缩写,

或者指定从backports源里安装:

1
$ sudo apt install tmux -t stretch-backports

还可以查看源里多个版本的详细信息:

1
2
3
4
5
6
7
8
9
$ apt-cache show tmux
Package: tmux
Version: 2.8-1~bpo9+1
Installed-Size: 677
...
Package: tmux
Version: 2.3-4
Installed-Size: 620
...

cassandra 2.2.6环境,有一台种子节点硬件故障,半年以后才修复重新上线。
其数据已经落后太多,而cassandra并不会在其重新上线后自动进行数据同步。
nodetool repair应该可以使其数据重新同步,但是那速度是无法忍受的,因此使用nodetool rebuild来重建其数据。

首先停止cassandra服务

1
$ sudo systemctl stop cassandra

或者

1
$ sudo service cassandra stop

然后删除掉数据目录下system和用户keyspace的所有数据
$ sudo rm -rf /var/lib/cassandra/data/system/*
$ sudo rm -rf /var/lib/cassandra/data/your_keyspaces/*

1
$ sudo rm -rf /var/lib/cassandra/*

如果不清除用户的keyspace,rebuild的时候并不会自动清除,而且rebuild是全量而不是增量,所以那些数据会成为垃圾数据,如果数据量很大,应该提前清除掉。

对于种子节点,还应该确认auto_bootstrap参数已经设置为false。

启动cassandra服务,执行rebuild

1
2
$ sudo service cassandra start
$ nodetool rebuild -- name_of_existing_data_center

指定源数据中心时,要指定与当前节点所在数据中心不同的数据中心。

查看rebuild进度

1
watch -n 10 'nodetool netstats | grep "Receiving\|Sending" | gawk {'"'"' print $1" - "$11/$4*100"% Complete, "($4-$11)/1024/1024/1024" GB remaining" '"'"'}'

等nodetool rebuild结束重建就算完成了,其实这与添加新的节点差别不大,不过就是原来的环境,所有的配置都不用动罢了。

同步完成后可以看看用户表的统计信息:

1
$ nodetool tablestats keyspace_name.table_name

updated:06/22/2019

这次种子节点下线重做RAID,系统重新安装,cassandra版本为2.2.14

rebuild的时候提示:

1
2
3
4
$nodetool rebuild -- DC2

nodetool: Unable to find sufficient sources for streaming range (2952258499581076301,2996932853512195336\] in keyspace system_traces
See 'nodetool help' or 'nodetool help <command>'.

需要将keyspace system_traces的replication strategy设置为NetworkTopologyStrategy并将其分布到所有的数据中心,其默认设置为SimpleStrategy

1
cqlsh> ALTER KEYSPACE system_traces WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1':2,'DC2':1};

keyspace system_distributed的replication strategy也应该设置为NetworkTopologyStrategy并将其分布到所有的数据中心

1
cqlsh> ALTER KEYSPACE system_distributed WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1':2,'DC2':1};

References:
[1]Unable to find sufficient sources for streaming range (,] in keyspace
[2]Unable to find sufficient sources for streaming range in keyspace
[3]system_distributed and system_traces keyspaces use hard-coded replication factors

怎么找到C源程序中没有被引用的function/死代码?
GCC的CFLAGS -Wall -Wextra只能报告未使用的变量,而函数要到代码全部链接完成,才能知道哪些是没有被任何代码引用的,为时已晚。

在编译链接时可以组合使用CFLAGS: -ffunction-sections -fdata-sections 和 LDFLAGS: -Wl,-gc-sections在目标文件里移除未使用的代码,那么如何在源文件里找到这些函数呢?

一个相当简单的办法,编译完成后,对比ELF目标文件和所有obj对象文件中符号表中符号的差异,就这一知道哪些函数在最终的目标文件中被移除了,也就是无用的函数。

首先编译代码:

1
$ cc foo.c -o foo -fdata-sections -ffunction-sections -Wl,--gc-sections -save-temps

注意要使用参数-save-temps保留中间文件,要用到是*.o对象文件
注意要保留符号表,不要strip all
gcc的--gc-sections在clang中对应的是-dead_strip

然后使用这个脚本find-unused-function.sh通过比较符号表找出从未被使用的函数名字

在工程目录下执行

1
$ ./find-unused-function.sh foo .

生成的./DebugSymbol/symbols.unused-binary文件中记载了未被使用的函数名称。

References:
[1]C-code—Find-Unused-functions

编译时把数据和函数放到单独的section中,然后链接的时候抛弃掉未使用的section就可以了。

也就是组合使用CFLAGS: -ffunction-sections -fdata-sections 和 LDFLAGS: -Wl,--gc-sections

1
$ cc foo.c -o foo -Os -fdata-sections -ffunction-sections -Wl,--gc-sections -s

-s 选项剥离掉调试信息,可以进一步减小目标文件的尺寸。

References:
[1]Removing Unused Functions/Dead Codes with GCC/GNU-ld
[2]Re: Removing unused functions/dead code