当CentOS 8系统不能更新

本文转载自:

https://stackoverflow.com/questions/70963985/error-failed-to-download-metadata-for-repo-appstream-cannot-prepare-internal

今天闲来无事,想把自己的服务器升级一下:

sudo dnf -y update

然后就出错了!!!

Repository epel is listed more than once in the configuration
CentOS Linux 8 - AppStream
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist

找了一篇相同问题的帖子,开始一顿操作

先是导入8.3的gpg key:

wget 'http://mirror.centos.org/centos/8-stream/BaseOS/x86_64/os/Packages/centos-gpg-keys-8-3.el8.noarch.rpm'
sudo rpm -i 'centos-gpg-keys-8-3.el8.noarch.rpm'

然后切换repo源由centos-linux-repos调整为centos-stream-repos:

sudo dnf --disablerepo '*' --enablerepo=extras swap centos-linux-repos centos-stream-repos

最后更新所有软件到最新的稳定发行版:

sudo dnf distro-sync

发表在 系统 | 标签为 , | 留下评论

Linux磁盘共享和挂载简易手册

共享服务器和挂载服务器都需要安装如下软件

sudo yum -y install nfs-utils rpcbind

共享端(IP:192.168.1.100)

sudo vim /etc/exports

编辑配置文件,添加一行内容

/opt/nfs-folder 192.168.1.105(ro)

其中 /opt/nfs-folder 是需要共享的目录, 192.168.1.105 是可以访问该共享目录的目标IP地址。

启动 NFS 服务:

sudo systemctl enable --now rpcbind
sudo systemctl enable --now nfs

共享端配置完成。

挂载端(IP:192.168.1.105)

查看服务器提供共享的目录

showmount -e 192.168.1.100

先创建挂载目标目录

mkdir -p /opt/target

方式一:通过命令进行挂载(重启系统后失效)

mount -t nfs 192.168.1.100:/opt/nfs-folder/upload /opt/target -o proto=tcp

该命令可以将 192.168.1.100 的目录 /opt/nfs-folder/upload 挂载到本地 /opt/target ,其中挂载点可以是共享目录的子目录。

关闭挂载

umount -l /opt/target

方式二:通过配置文件

sudo vim /etc/fstab

编辑配置文件,在最后添加一行内容

192.168.1.100:/opt/nfs-folder/upload    /opt/target    nfs    defaults    0 0

重启系统或者重载挂载使之生效

mount -a

发表在 服务器, 系统 | 标签为 , | 留下评论

SFTP搭建简易手册

创建SFTP用户组

sudo groupadd sftp

创建SFTP用户并指定用户组为sftp

sudo useradd -g sftp -s /sbin/nologin -M sftpuser

创建SFTP根目录,该根目录所属用户必须为root,权限不能低于755。

sudo mkdir -p /opt/sftp
sudo chown root:sftp /opt/sftp
sudo chmod 755 /opt/sftp

SFTP根目录下按照用户名直接匹配目录路径(其他方式参见相关文档),创建用户SFTP根目录

sudo mkdir -p /opt/sftp/sftpuser
sudo chown sftpuser:sftp /opt/sftp/sftpuser
sudo chmod 755 /opt/sftp/sftpuser

其他SFTP用户可以按照同样的方法配置OWN。

以 SODU 身份编辑 /etc/ssh/sshd_config 配置,在配置文件最下面添加如下内容:

Subsystem sftp internal-sftp -l INFO -f AUTH
Match Group sftp
ChrootDirectory /opt/sftp/%u
ForceCommand internal-sftp -l INFO -f AUTH
AllowTcpForwarding no
X11Forwarding no

此处 %u 按照用户匹配同名路径。

重启 SSH 服务:

sudo systemctl restart sshd

测试 SFTP 连通性:(-P指定端口,默认22)

sftp -P 22 sftpuser@localhost

完成。

发表在 服务器 | 标签为 , | 留下评论

创建一个带事务和错误日志的存储过程

首先创建日志表用于记录存储过程执行错误信息

CREATE TABLE LOG_PROCEDURE
(
   ID                   BIGINT NOT NULL AUTO_INCREMENT,
   PRCD_NAME            VARCHAR(64) NOT NULL,
   MYSQL_ERRNO          VARCHAR(8),
   RETURN_STATE         VARCHAR(8),
   MESSAGE              TEXT,
   CREATE_TIMESTAMP     DATETIME DEFAULT CURRENT_TIMESTAMP,
   MODIFY_TIMESTAMP     DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY (ID)
);

然后创建一张测试数据表,用于测试存储过程

CREATE TABLE DATA_TEST
(
   ID                   BIGINT NOT NULL AUTO_INCREMENT,
   COL_A                VARCHAR(64),
   PRIMARY KEY (ID)
);

创建存储过程,在存储过程事务中和事务后分别往测试数据表里存入一条记录,事务中另外试图往一张不存在的表里存入一条记录。

DELIMITER $$
DROP PROCEDURE IF EXISTS PRCD_TEST$$
CREATE PROCEDURE PRCD_TEST (
	/** 定义IN,OUT */
)
BEGIN
	/** 定义变量 */

	/** 定义错误捕获 */
	DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING
	BEGIN
		/** 获取错误内容 */
		GET DIAGNOSTICS CONDITION 1 @p1 = MYSQL_ERRNO, @p2 = RETURNED_SQLSTATE, @p3 = MESSAGE_TEXT;
		ROLLBACK;

		/** 错误信息存入日志表 */
		INSERT INTO LOG_PROCEDURE(PRCD_NAME, MYSQL_ERRNO, RETURN_STATE, MESSAGE)
			VALUES ('PRCD_TEST', @p1, @p2, @p3);

		/** 失败后 */
		INSERT INTO DATA_TEST(COL_A) VALUE('INSERT_FAILED');
	END;

	/** 开启事务 */
	START TRANSACTION;

	/** 执行内容 */
	INSERT INTO DATA_TEST(COL_A) VALUE('TEST_01');
	INSERT INTO NOT_EXIST_TABLE(ID) VALUE('ERROR');
	INSERT INTO DATA_TEST(COL_A) VALUE('TEST_02');

	/** 提交事务 */
	COMMIT;

	/** 成功后 */
	INSERT INTO DATA_TEST(COL_A) VALUE('INSERT_SUCCESS');
END$$
DELIMITER ;

调用存储过程

CALL PRCD_TEST();

执行结果

错误日志表 LOG_PROCEDURE 里的记录

IDPRCD_NAMEMYSQL_ERRNORETURN_STATEMESSAGE
1PRCD_TEST114642S02Table ‘schema.not_exist_table’ doesn’t exist

再看看测试数据表

IDCOL_A
2INSERT_FAILED

简单说明一下执行过程:

  1. 开启事务
  2. 往测试数据表里存入TEST_01(ID:1)
  3. 往NOT_EXIST_TABLE存入记录(异常)
  4. SQLEXCEPTION被捕获,获取错误信息
  5. 事务回滚
  6. 将获取到的错误信息存入错误日志表
  7. 往测试数据表里存入INSERT_FAILED(ID:2)

所以测试数据表里的记录ID是2而不是1

发表在 数据库 | 标签为 , , | 留下评论

服务器基本安全设置

添加个人用户

(本文统一使用ohmmx)

以root身份执行命令

adduser -m ohmmx

如果想要删除用户,以root身份执行命令

userdel -r ohmmx

添加用户鉴权

使用密码登录

sudo passwd ohmmx

输入两次密码确认以后,该用户可以使用密码进行登录。

使用SSHKey登录

创建 {$用户目录}/.ssh/authorized_keys (该路径可以在 /etc/ssh/sshd_config 中配置) 文件并存入,此处路径为 /home/ohmmx/.ssh/authorized_keys

其中 .ssh权限700,authorized_keys文件权限600。

以root身份更改文件所属者:

chown -R ohmmx:ohmmx .ssh

将本地客户端工具生成的公私钥对中的公钥存入文件,例如:

ssh-rsa AAAAB………2Q== ohmmx

其中两个等号后面为备注,标注该公钥是由ohmmx用户使用,多用户配置时该注释能清晰区分各用户对应公钥。

给用户添加SUDO权限

为避免日常使用root用户,在操作过程中产生的错误操作,日常建议使用个人用户,并添加sudo权限,在需要使用root身份的时候单独使用sudo权限执行命令。

以root身份执行命令

visudo

在 ## Allow root to run any commands anywhere 下面root用户下面添加一行内容:

ohmmx  ALL=(ALL)  ALL

这样在执行sudo命令时要求输入用户自己的个人密码;

也可以配置为不用输入密码直接执行sudo命令

ohmmx  ALL=(ALL)  NOPASSWD:ALL

关闭Selinux安全管理

Selinux为Linux系统内部用户账户控制设置模块,任何权限都需要配置申请,这里先将其关闭。

sudo vim /etc/selinux/config

将enforcing调整为disabled

SELINUX=disabled

调整SSH设置

sudo vim /etc/ssh/sshd_config

只对一些相对重要的参数进行说明:

Port 22

SSH链接端口,默认22,配置文件默认注释掉了。需要修改端口先去掉注释,并更改端口为指定数字。

ListenAddress 0.0.0.0

SSH监听地址,默认0.0.0.0。此处不用调整;如果需要调整,请学习局域网网关、网段相关知识。

PermitRootLogin yes

是否允许root用户通过SSH链接,默认允许。此处需要调整为no关闭,只允许个人用户通过SSH链接,如果需要root身份,可以使用sudo命令进行操作。

PubkeyAuthentication yes

是否允许通过公钥登录,默认允许。

AuthorizedKeysFile      .ssh/authorized_keys

公钥保存路径。修改此处配置,需要对应调整公钥文件路径。

PasswordAuthentication yes

是否允许通过密码登录,默认允许。可以将此处关闭,强制要求使用公钥登录。

X11Forwarding yes

图形化远程界面,默认允许。此处可以关闭,通常用不到。

防火墙设置(如果修改了SSH默认端口)

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

如果要以service的形式添加防火墙设置,将文件存放到/etc/firewalld/services/路径。(不要存放到/usr/lib/firewalld/services/路径,该路径在系统更新时会恢复默认值)。

/etc/firewalld/services/下的配置文件会覆盖掉/usr/lib/firewalld/services/路径下的配置,比如将/usr/lib/firewalld/services/ssh.xml复制到/etc/firewalld/services/ssh.xml并修改端口为2222,则ssh服务生效的就是2222端口。

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
发表在 系统 | 标签为 , , | 留下评论

空值排序查询

在表里某个字段含有空值(NULL),这时候想把空值的统一排到前面或者后面,然后并不影响其他有值记录的正常排序。

方法一:在排序里添加判断

SELECT * FROM TABLE1 t ORDER BY t.COL1 IS NULL, t.COL1; -- 空值排后
SELECT * FROM TABLE1 t ORDER BY t.COL1 IS NOT NULL, t.COL1; -- 空值排前

同理也可以使用 IFNULL() 或者 ISNULL() 等方法在排序里进行判断。

方法二:将空值字段打个标记,再使用内联视图进行二次查询。

SELECT
	* 
FROM
	( SELECT t.*, CASE WHEN t.COL1 IS NULL OR t.COL1 = '' THEN 1 ELSE 0 END IS_NULL FROM TABLE1 t ) v 
ORDER BY
	v.IS_NULL DESC,
	v.COL1
发表在 数据库 | 标签为 , | 留下评论

Steam愿望单整理

安装插件 Augmented Steam:

https://chrome.google.com/webstore/detail/dnhpnfgdlenaccegplpojghhmaamnnfp

会在愿望单页面

https://store.steampowered.com/wishlist/

顶端看见加入了两个按钮:清空愿望单 和 导出愿望单

点击导出愿望单,选择导出类型 纯文本,文本格式里填入内容

%title%, %id%, %appid%, %url%, %release_date%, %price%, %discount%, %base_price%, %type%, %note%
title:游戏名称
id:相对路径。如:app/570
appid:游戏ID。如:570
url:游戏网址。如:https://store.steampowered.com/app/570/
release_date:发售日期。
price:当前区域价格(含折扣)。
discount:折扣率。
base_price:基准价格。
type:类型。Game/DLC
note:用户自定义备注(插件功能)。

可以选择需要的字段进行导出。

这时候会发现导出的愿望单游戏数量有可能少于总愿望单里游戏数(在导出愿望单按钮右边的愿望单按钮上有个数量)。

这是由于愿望单里有一些游戏已经下架,愿望单里已经看不见了,但是依然计入愿望单总数量里,这时候我们就要把他们找出来从愿望单里删掉。

在愿望单页面打开开发者工具(默认快捷键F12)

切换到 Console 标签栏,在下面输入框(有个大于号 > 提示符)输入内容:

var str = "";
for (var i=0; i<g_rgWishlistData.length; i++) {
	str += g_rgWishlistData[i].appid + "\n";
}
console.log(str);

回车执行。会发现在控制台里打印出了所有的愿望单游戏的 appid。

这时候我们将这一批 appid 和前面用插件导出的 appid 进行比较。

有很多种比较方法。这里举一个例子:

先将两次导出的愿望单列表分别保存到一个文本文件中,用 Excel 打开文本文件并进行排序,用比较工具 BeyondCompare 进行比较,视图显示差异,就找到在我们愿望单里并已经下架了的游戏 appid。

这时候可以去 SteamDB 查询一下该游戏是什么,是不是确定要从愿望单里删除,还是留在愿望单里做个纪念。

在确定要从愿望单里删除这个游戏后,我们回到愿望单页面,打开开发者工具,切换到 Console 标签栏,一气呵成。然后输入内容:

$J.ajax({type: "POST", url: g_strWishlistBaseURL + 'remove/', data: {'appid': 570, sessionid: g_sessionID} });

在 appid 处输入我们想要从愿望单删除的游戏,回车执行,完成收工。

发表在 Steam | 标签为 , | 留下评论

Windows环境下安装Redis

下载地址:https://github.com/MicrosoftArchive/redis/releases

下载zip文件手动安装,方便控制。

直接启动Redis,不添加系统服务,关闭窗口服务结束。

redis-server.exe redis.windows.conf

使用系统服务。添加、启动、关闭、卸载命令如下,其中 RedisServer1 是系统服务器的名称,可以设置为其他名称。

redis-server.exe --service-install redis.windows.conf --service-name [RedisServer1] --loglevel verbose
redis-server.exe --service-start --service-name [RedisServer1]
redis-server.exe --service-stop --service-name [RedisServer1]
redis-server.exe --service-uninstall --service-name [RedisServer1]

启动多个 Redis 服务,复制文件夹到另一处,更改配置文件 redis.windows.conf 里的 ip 和端口就行,其他操作跟前面一样。

访问 Redis 需要密码,更改配置文件 redis.windows.conf ,注释掉

# requirepass foobared

前面的 # 号,并把 foobared 更改为自己需要的密码即可。

发表在 服务器 | 标签为 | 留下评论

关于Windows命令行的字符集

win10自带2个命令行工具,cmd 和 powershell,默认字符集 936(GBK)。其他常用的字符集 437(美国)、65001(UTF-8)。

查看当前窗口字符集:

chcp

更改当前窗口字符集:

chcp 65001

我们想要在打开窗口的时候自动设置好字符集,不然每次都得设置一次可太麻烦了。

方法一:系统设置(以下三个方法打开区域设置)

1. 开始 – 设置 – 时间和语言 – 日期、时间和区域格式设置 – 其他日期、时间和区域设置 – 区域

2. 控制面板(小图标) – 区域

3. 运行 – intl.cpl

区域设置 – 管理(标签) – 更改系统区域设置… – [选中]Beta版:使用 Unicode UTF-8 提供全球语言支持 – 重启系统

重启以后 cmd 和 powershell 默认都使用 65001(UTF-8)字符集。

但是有个比较严重的问题,有部分软件对 UTF-8 支持不好会出现乱码。

方法二:功能设置

针对 cmd

打开注册表,运行 – regedit

[HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\Autorun] 修改值为 chcp 65001 >NUL

如果在 Command Processor 下没有 Autorun,自行添加一条 字符串值(S)。

这样在启动 cmd 的时候会先执行 chcp 65001 将字符集调整为 UTF-8。

针对 powershell

以管理员启动 powershell,执行

New-Item $PROFILE -ItemType File -Force

在 powershell 的默认启动目录下创建启动脚本 %USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1,再执行命令

Set-ExecutionPolicy Unrestricted

一定要管理员才能执行。这个命令允许 powershell 启动的时候执行启动脚本,如果不执行该命令会在启动 powershell 的时候提示禁止运行脚本。

编辑启动脚本 Microsoft.PowerShell_profile.ps1,添加一行内容

$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

以后启动 powershell 默认使用 65001(UTF-8)字符集。

发表在 系统 | 标签为 , | 留下评论

数据库自动备份

先设置好默认的用户名和密码,避免在脚本里写密码

vim ~/.my.cnf
[mysqldump]
user=[username]
password=[password]

写一个脚本把备份脚本写进去

vim dbbackup.sh
NOW=$(date +"%Y%m%d%H%M%S")
mysqldump -h [host] -P [port] [dbname] | xz > [path]/db_[dbname]_$NOW.sql.xz

给脚本添加执行权限

chmod +x dbbackup.sh

备份多个库可以写多条 mysqldump,后面的时分秒 %H%M%S 可以酌情去掉。

添加定时任务

crontab -e
0 3 * * * [path]/dbbackup.sh

系统的定时任务最小单位是秒,这里会在每天的3点0分执行一次。

发表在 数据库 | 标签为 , | 留下评论