分类目录归档:技术

Nginx Proxy Manager – Docker 建站最佳伴侣

很长一段时间中,我都在思考容器建站的可行性。

容器有诸多益处,各类好处就不一一列举了。

在企业场景下,K8s 几乎一骑绝尘,可以完成大规模集群统一管理,完成几乎所有 Web 资源的自动调度。

但强大功能的代价,就是系统本身势必占用一部分资源,这就不适合大部分小网站、小企业去使用了。

传统建站一般是使用虚拟主机的形式,使用宝塔、AppNode、cPanel 之类的面板管理单节点站点,流量大了给服务器扩容、负载均衡、数据库外挂之类的也就解决了。

这种方案很适用于 LAMP 组合场景,可以让自己的想法快速成为现实。

在当代,各种新式编程语言大行其道,PHP 的时代似乎已经过去,容器成为更复杂运行环境的最佳载体。

作为个人站长,近几年部署应用都会优先考虑使用容器,还尝试过 k3s 组建轻量 k8s 集群的方案,使用近一年下来总有种大炮打蚊子的感觉。

说了这么多,就是想引出一种适用于当代 WEB 服务部署,容器化,但又不需要多台服务器的容器方案。

方案的关键技术为 Docker + Nginx 的组合。

上层采用 Portainer + Nginx Proxy Manager , 满足 UI 管理的需求。

部署方法

下面简单讲一下部署方法:

Docker

因为 Docker 的部署方法网上资源较多,这里就不列举了,下面默认已安装 docker .

Portainer

Portainer 是当下比较好用的一款 Docker Web GUI ,使用起来可以满足大部分需求了,部署方法也很简单,类似这样:

$ docker run -d
--network myDefault
--restart=always
--name="portainer" -p 9000:9000
-v /var/run/docker.sock:/var/run/docker.sock
-v portainer_data:/data 6053537/portainer-ce

其中的 myDefault 是自定义网桥,为兼容 docker-compose 等应用的外部访问,在这里不建议使用 Docker 默认网桥。

如果没有报错,就可以通过 9000 端口访问了,后面可以使用 nginx 反代此端口就可以关闭 9000 端口外部访问了。

Nginx Proxy Manager

这是一款 nginx web gui,使用下来体验不错,貌似内嵌了 openrusty,基本可以满足 Docker 反代、HTTPS 访问等的 GUI 配置需求了

使用如下 docker-compose 部署,可以直接在 portainer 操作:

version: '3'
services:
  app:
    hostname: nginx-proxy-manager
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
networks:
  default:
    external: true
    name: myDefault

打开后台:

http://127.0.0.1:81

默认管理账户:

Email:    admin@example.com
Password: changeme

效果展示

我在这里使用的是某位大佬汉化的 Portainer,为的是熟悉一下界面,简化操作,等熟悉了还是建议切回官方版本。

后面部署应用就在这里一站式搞定了,暴露外部访问时,就用 Nginx Proxy Manager:

反代配置界面如下:

以后在这里部署 Docker 应用,就可以很方便的暴露外部访问了,配了 Portainer 较好的生态和灵活的配置,几乎没有什么限制。

总结

本文介绍了一种轻量(1C2G 足矣)、容器化(Docker+Portainer)、自动化(Nginx Proxy Manager 自动 Https)的个人网站搭建方案,该方案几乎可以适应所有场景,更重要的是一台 1C2G 的服务器就足矣支撑数十个小应用。

自己使用或是外部访问都极其方便,再也不用纠结使用哪家面板,再也不用担心面板安全问题了。

我自己的图床、博客、Miniflux、网站统计、数据库以及一些自己开源的应用未来都计划部署在这里。

这就是今天分享的内容了,希望对你有用。

最后提醒一句,本文涉及的部署命令和配置文件随时有可能过时,请以官方文档为准。

参考文献

OpenEuler 防火墙放通端口 (以 8084 为例)

最近使用 OpenEuler 部署项目,发现防火墙放通端口的方法找不到,因此在这里记录:

[root@localhost Porting-advisor_2.5.RC1_linux-x86-64]# firewall-cmd --query-port=8084/tcp --permanent
no
[root@localhost Porting-advisor_2.5.RC1_linux-x86-64]# firewall-cmd --add-port=8084/tcp --permanent
success
[root@localhost Porting-advisor_2.5.RC1_linux-x86-64]# firewall-cmd --reload
success
[root@localhost Porting-advisor_2.5.RC1_linux-x86-64]# firewall-cmd --query-port=8084/tcp --permanent
yes

kali linux 配置 xrdp 远程桌面服务

xrdp 的配置让我充满疑惑,今天误打误撞完成了 kali 下的 xrdp 配置,能够顺利远程桌面进入 kali,这里记录一些可能必须的步骤,以备后用。

首先按照 kali 官网给出的 xrdp 配置脚本:

#!/bin/sh
echo "[i] Updating and upgrading Kali (this will take a while)"
apt-get update
apt-get dist-upgrade -y

echo "[i] Installing Xfce4 & xrdp (this will take a while as well)"
apt-get install -y kali-desktop-xfce xorg xrdp

echo "[i] Configuring xrdp to listen to port 3390 (but not starting the service)"
sed -i 's/port=3389/port=3390/g' /etc/xrdp/xrdp.ini

保存后 sudo 执行,自动配置 xrdp。

如果下载慢可以配一下 USTC Kali 软件源。

之后设定默认命令行启动,否则无法加载远程桌面:

# 命令行启动
$ systemctl set-default multi-user.target

# 图形界面启动
$ systemctl set-default graphical.target

之后使能 xrdp 服务:

$ systemctl enable xrdp
$ systemctl start xrdp

避免 ssl 证书无法验证,将 xrdp 用户加入 ssl-cert 用户组:

sudo adduser xrdp ssl-cert

之后可以重启试一下能否成功,记得官方配置端口为 3390 而非 3389:

$ reboot

如果不行配置一下这个再重启尝试:

# To set the system default to xfce4:-
$ **sudo update-alternatives --config x-session-manager**
There are 3 choices for the alternative x-session-manager (providing /usr/bin/x-session-manager).

  Selection    Path                    Priority   Status
------------------------------------------------------------
* 0            /usr/bin/gnome-session   50        auto mode
  1            /usr/bin/gnome-session   50        manual mode
  2            /usr/bin/startxfce4      50        manual mode
  3            /usr/bin/xfce4-session   40        manual mode

Press  to keep the current choice[*], or type selection number: **3**
update-alternatives: using /usr/bin/xfce4-session to provide /usr/bin/x-session-manager (x-session-manager) in manual mode

Try that

然后应该就可以了。如果不行欢迎留言。

参考文献

macOS 使用 arping 扫描 ip 冲突

最近工作网络不稳定,多个常用 IP 出现冲突,就连 DHCP 获取到的 IP 也会立刻冲突,原因等待相关人员去解决,今天简单记录 macOS 下 IP 冲突检测的原因。

一般检查 IP 是否被占用的方法是使用 ping

$ ping 119.29.29.29
PING 119.29.29.29 (119.29.29.29): 56 data bytes
64 bytes from 119.29.29.29: icmp_seq=0 ttl=50 time=14.477 ms
64 bytes from 119.29.29.29: icmp_seq=1 ttl=50 time=15.033 ms
64 bytes from 119.29.29.29: icmp_seq=2 ttl=50 time=15.330 ms
^C
--- 119.29.29.29 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 14.477/14.947/15.330/0.354 ms

但是这种方法看不到ip冲突,如果出现多个机器占用同个 IP,可以利用arp协议查一下 MAC 地址:

# macOS 下这样安装
$ brew install arping
# 使用 alias 定义快速使用别名
$ alias arping='sudo /opt/homebrew/opt/arping/sbin/arping'

另外发现 m1 下的 brew 安装 arping 默认不会进入 PATH ,因此在这里手动设定一个别名,方便使用。

之后扫描,如果出现 IP 冲突,可以看到有多个 MAC 地址回应:

$ sudo /opt/homebrew/opt/arping/sbin/arping 192.168.5.79
Password:
ARPING 192.168.5.79
60 bytes from 6a:f2:77:bd:bf:16 (192.168.5.79): index=0 time=463.000 usec
60 bytes from 6a:29:af:20:80:7f (192.168.5.79): index=1 time=1.002 msec
60 bytes from 6a:f2:77:bd:bf:16 (192.168.5.79): index=2 time=582.000 usec
60 bytes from 6a:29:af:20:80:7f (192.168.5.79): index=3 time=1.182 msec
60 bytes from 6a:f2:77:bd:bf:16 (192.168.5.79): index=4 time=658.000 usec
60 bytes from 6a:29:af:20:80:7f (192.168.5.79): index=5 time=1.117 msec
60 bytes from 6a:f2:77:bd:bf:16 (192.168.5.79): index=6 time=772.000 usec
60 bytes from 6a:29:af:20:80:7f (192.168.5.79): index=7 time=1.096 msec
^C
--- 192.168.5.79 statistics ---
4 packets transmitted, 8 packets received,   0% unanswered (4 extra)
rtt min/avg/max/std-dev = 0.463/0.859/1.182/0.257 ms

还可以通过 arping 来查看是否 IP 被占用,有些机器会禁止 PING 检测,使用 arp 这类二层协议检测占用情况会更准确些。

参考文献

macOS12 使用 UTM 体验 macOS 13 Ventura (多图预警)

UTM 是苹果 IOS、macOS 生态下的一款开源的虚拟机软件,底层基于 QEMU 或 Apple 虚拟化,能够在苹果操作系统上以半虚拟化(同 CPU 架构)或全虚拟化(异构 CPU 系统)的形式运行 Linux、Windows 以及 macOS。

macOS 13 (Ventura) 是苹果公司用于麦金塔桌面操作系统macOS的第19个主要版本,于2022年6月7日的苹果全球开发者大会(WWDC)上发布,成为macOS 12 Monterey的继任版本。此版macOS命名自加州南部的滨海旅游胜地范朵拉市

基于此前苹果系统的一些历史丑闻,导致本人在内的许多人对苹果推送的新固件保持谨慎态度。作为生产力存在的 macOS 更加需要小心谨慎了。

但一味的观望总是毫无进展的,还是上手体验一番最有说服力。虽然在 macOS 12 下使用 UTM 不可以直接启动 macOS 13 虚拟机,但是可以通过安装 macOS 12 虚拟机然后再更新到 macOS 13 的形式体验到最新的 macOS。

下面介绍方法和效果展示,多图预警!!

材料准备

为了安装 macOS 12 虚拟机,需要至少准备以下资源:

  • UTM
  • macOS12 IPSW 文件(约14GB)
  • 大约 64GB 的磁盘空间

其中 UTM 用于启动虚拟机,按照官网的流畅安装即可,非常简单。

IPSW 文件可理解为苹果生态下的 ISO 镜像,其中包含所有系统资源,可通过 这里这里 下载到 macOS 12 系统镜像。

IPSW(iPhone软件)是一种文件格式,用于为装有Apple芯片的设备安装iOS,iPadOS,tvOS,HomePod和最近的macOS固件。

需要注意的是,macOS 13 无法直接在 macOS 12 下启动,因此即使能够获取到 macOS 13 的 IPSW 文件,也无法启动。

磁盘空间需要预留至少 64GB,因为本人在尝试分配 64G 硬盘后,发现安装过程中几乎全部耗尽,如果空间不足会导致虚拟机卡死。

一切准备就绪,就可以开始了。

开始 Ventura 之旅

以下使用图片加注释的形式进行,按照图示一步一步走过来即可,赶时间也可以直接看图片效果:

这一步载入 macOS IPSW 文件

建议磁盘选择 64GB,32 GB 无法安装 macOS 13

等待系统安装

登入 macOS 13

系统信息

软件展示

台前调度

总结

使用 UTM 足以体验所有 macOS13 的所有新功能,用来评估是否可以用于自己的日常工作,以及个人喜好,避免降级。

本文介绍了 UTM 配置 macOS 12 虚拟机并升级到 macOS 13 的全过程,展示了 macOS 13 变动较大的设置、时钟、天气以及台前调度等功能,希望对大家起到一些参考意义,若有问题欢迎留言。

参考文献

根本解决C程序 ignoring return value of ‘***’

最近在移植一个 C 项目时出现如下报错:

xxxxxx.c:990:4: error: ignoring return value of ‘chroot’, declared with attribute warn_unused_result [-Werror=unused-result]
  990 |    chroot("/");

之所以报错等级为 Error ,是因为 GCC 编译具有参数 -Werror,将警告当作错误:

gcc -std=gnu99 -Wall -Werror -Wno-unknown-pragmas -Wno-strict-aliasing -Wpedantic -g -O2 -Wl,-z,relro -I. -D_FILE_OFFSET_BITS=64 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/fuse -c -o xxxxxx.o xxxxxx.c -MMD -MT pmxcfs.o -MF xxxxxx.o.d

去掉这一编译参数治标不治本。最根本的解决办法是去源码找到出问题的地方,处理一下返回值,或者这样手动忽略错误,并辅以注释:

- chown(RUNDIR, 0, cfs.gid);
+ # TODO 临时处理,忽略返回值
+ # 后期需根据实际情况处理错误码
+ if(chown(RUNDIR, 0, cfs.gid)){};

再次编译解决。

参考文献

Linux 使用 diff 分栏对比文本差异

首先看一下帮助文档:

$ diff --help  
用法:diff [选项]... 文件列表  
逐行比较<各文件>。  

长选项的必需参数也是相应短选项的必需参数。  
     --normal                  以正常的 diff 方式输出 (默认)  
 -q, --brief                   只有在文件不同时报告  
 -s, --report-identical-files  当两个一样时仍然显示结果  
 -c, -C NUM, --context[=NUM]   同时输出 NUM 行(默认为 3 行)的复制上下文内容  
 -u, -U 数量, --unified[=数量] 输出 <数量>(默认为 3)行一致化上下文  
 -e, --ed                      以 ed script 方式输出  
 -n, --rcs                     以 RCS diff 格式输出  
 -y, --side-by-side            以两栏的格式输出  
 -W, --width=数量              每行显示最多 <数量>(默认 130)个字符  
     --left-column             当有两行相同时只显示左边栏的一行  
     --suppress-common-lines   当有两行相同时不显示  

 -p, --show-c-function         显示每个变更位于哪个 C 函数中  
 -F, --show-function-line=正则 显示匹配给定<正则>表达式的最近一行  
     --label 标签              使用给定<标签>替代文件名和时间戳  
                                 (可以重复)  

 -t, --expand-tabs             将输出中的 tab 转换成空格  
 -T, --initial-tab             每行先加上 tab 字符,使 tab 字符可以对齐  
     --tabsize=数字           TAB 格的宽度,默认为 8 个打印列宽  
     --suppress-blank-empty    在空的输出行之前去除空白或制表符  
 -l, --paginate                将输出送至 “pr” 指令来分页  

 -r, --recursive                 连同所有子目录一起比较  
     --no-dereference            不要跟随符号链接  
 -N, --new-file                  不存在的文件以空文件方式处理  
     --unidirectional-new-file   若第一文件不存在,以空文件处理  
     --ignore-file-name-case     忽略文件名大小写的区别  
     --no-ignore-file-name-case  不忽略文件名大小写的区别  
 -x, --exclude=模式              排除匹配 <模式> 的文件  
 -X, --exclude-from=文件         排除所有匹配在<文件>中列出的模式的文件  
 -S, --starting-file=文件        当比较目录時,由<文件>开始比较  
     --from-file=文件1           将<文件1>和操作数中的所有文件/目录作比较;  
                                   <文件1>可以是目录  
     --to-file=文件2             将操作数中的所有文件/目录和<文件2>作比较;  
                                   <文件2>可以是目录  

 -i, --ignore-case               忽略文件内容大小写的区别  
 -E, --ignore-tab-expansion      忽略由制表符宽度造成的差异  
 -Z, --ignore-trailing-space     忽略每行末端的空格  
 -b, --ignore-space-change       忽略由空格数不同造成的差异  
 -w, --ignore-all-space          忽略所有空格  
 -B, --ignore-blank-lines        忽略任何因空行而造成的差异  
 -I, --ignore-matching-lines=正则 若某行完全匹配 <正则>,则忽略由该行造成的差异  

 -a, --text                      所有文件都以文本方式处理  
     --strip-trailing-cr         去除输入内容每行末端的回车(CR)字符  

 -D, --ifdef=名称                输出的内容以 ‘#ifdef <名称>’ 方式标明差异  
     --GTYPE-group-format=GFMT   以 GFMT 格式处理 GTYPE 输入行组  
     --line-format=LFMT          以 LFMT 格式处理每一行资料  
     --LTYPE-line-format=LFMT    以 LFMT 格式处理 LTYPE 输入的行  
   这些格式化选项提供对 diff 输出的精细控制,从而泛化 -D/--ifdef。  
   LTYPE 可以是 “old”、“new” 或 “unchanged”。GTYPE 可以是 LTYPE 的选择  
   或是 “changed”。  
   (仅)GFMT 可包括:  
     %<  该组中每行属于<文件1>的差异  
     %>  该组中每行属于<文件2>的差异  
     %=  该组中同时在<文件1>和<文件2>出现的每一行  
     %[-][宽度][.[精确度]]{doxX}字符  以 printf 格式表示该<字符>代表的内容  
       大写<字符>表示属于新的文件,小写表示属于旧的文件。<字符>的意义如下:  
         F  行组中第一行的行号  
         L  行组中最后一行的行号  
         N  行数 ( =L-F+1 )  
         E  F-1  
         M  L+1  
     %(A=B?T:E)  如果 A 等于 B 那么 T 否则 E  
   (仅)LFMT 可包括:  
     %L  该行的内容  
     %l  该行的内容,但不包括结束的换行符  
     %[-][宽度][.[精确度]]{doxX}n  以 printf 格式表示的输入行号  
   GFMT 或 LFMT 都可包括:  
     %%        %  
     %c'C'     单个字符 C  
     %c'\OOO'  八进制码 OOO 所代表的字符  
     C         字符 C(处上述转义外的其他字符代表它们自身)  

 -d, --minimal            尽可能找出最小的差异集  
     --horizon-lines=数量 保持指定行数的一致前后缀  
     --speed-large-files  假设文件十分大而且文件中含有许多微小的差异  
     --color[=何时]       给输出上色;“何时”可以是“never”(从不)、  
                            “always”(总是)或“auto”(自动,默认);  
                            仅指定 --color 与 --color='auto' 效果相同  
     --palette=调色板     在 --color 选项启用时使用的颜色;<调色板>参数应当是  
                            一个冒号分隔的列表以提供 terminfo capabilities 信息  

     --help               显示此帮助信息并退出  
 -v, --version            输出版本信息并退出  

 <文件列表> 的格式可以是“文件1 文件2”、“目录1 目录2”、“目录 文件”或  
     “文件 目录”。  
如果使用 --from-file 或 --to-file 选项,<文件名> 的格式则不受限制。  
如果 FILE 是 “-”,则由标准输入读取内容。  
如果输入相同,则退出状态为 0;1 表示输入不同;2 表示有错误产生。  

报告程序错误到: bug-diffutils@gnu.org  
报告翻译错误到: https://translationproject.org/teams/zh_CN.html  
GNU diffutils 主页: <https://www.gnu.org/software/diffutils/>  
使用 GNU 软件的通用帮助:<https://www.gnu.org/gethelp/>

用的时候可以横排查看不同的地方:

$ diff pmxcfs.kylin.e pmxcfs.debian10.e -y -W 180

使用 -y 表示两列查看,使用 -W 设定宽度,这样就可以在终端里分栏查看文件差异:

参考文献

linux grep 过滤多个单词

有时会需要使用 grep 做多关键词匹配,这里给出集中方法,简单记录:

grep 'word1\|word2\|word3' /path/to/file
### Search all text files ###
$ grep 'word*' *.txt
### Search all python files for 'wordA' or 'wordB' ###
$ grep 'wordA*'\''wordB' *.py
$ grep -E 'word1|word2' *.doc
$ grep -e string1 -e string2 *.pl
$ grep -E "word1|word2" *.c
### Show all the lines that do not match given pattern/words/strings ###
$ grep -v 'bar\|foo' /dir1/dir2/file1
$ grep -E -v 'pattern1|pattern2' /path/to/file

参考文献