angie自动签发ssl配置
acme_client 99999_net https://acme-v02.api.letsencrypt.org/directory challenge=dns;
server {
listen unix:/run/acme-99999_net.sock;
server_name 99999.net *.99999.net;
acme 99999_net;
location @acme_hook_location {
acme_hook 99999_net uri=/angie.php;
proxy_pass http://API.SERVER;
proxy_read_timeout 560s;
proxy_send_timeout 560s;
proxy_set_header X-Acme-Hook $acme_hook_name;
proxy_set_header X-Acme-Challenge $acme_hook_challenge;
proxy_set_header X-Acme-Domain $acme_hook_domain;
proxy_set_header X-Acme-Keyauth $acme_hook_keyauth;
}
}
angie官方只写了fastcgi和php-fpm的配置,这里补全一下proxy_pass调用api的方式
示例参数说明:
99999.net是域名
99999_net是acme name (acme签发只签发ssl可以直接用域名,但是网站里面ssl_certificate维护的时候变量无法识别.必须用下划线_才能识别)
API.SERVER是接口服务器地址
uri=/angie.php是api接收具体uri地址
proxy_pass暂时只能走http, 走https会请求不到可能要用ngx_http_tunnel_module模块走tunnel_pass localhost:9000;
这里的server和 listen unix:/run/acme-99999_net.sock; 是http下的字段,用于专门管理acme,这里用server字段管理可以单独签证书, 也可以在 网站的server字段下加location字段 @acme_hook_location, 可以查看官方文档https://cn.angie.software/angie/docs/configuration/acme/#acme-config-hooks-minimal-configuration
X-Acme系列header是传送参数,这里用header方式,也可以走uri个get方式,但会造成明文泄露的问题.
HTTP_X_ACME_DOMAIN是请求的根域名,HTTP_X_ACME_KEYAUTH是_acme-challenge.99999.net的TXT值
$_SERVER['HTTP_X_ACME_HOOK']是传送remove和add动作,根据这个参数添加或者删除记录
API SERVER对子域名_acme-challenge添加删除TXT记录就行了,其他没有什么特殊设置了。
另外一种angie DNS托管方式验证方法:
acme_client 99999_net https://acme-v02.api.letsencrypt.org/directory challenge=dns;
server {
listen unix:/run/acme-99999_net.sock;
server_name 99999.net *.99999.net;
acme 99999_net;
}
第一步:解析一个A记录 例如 ns111.99999.net 到当前的angie公网IP,并开放53 UDP端口对外访问
第二步:设置_acme-challenge.99999.net一个NS记录到ns111.99999.net就可以托管到angie内部自动管理。
两种方式对自动内部管理签发通配符SSL证书方便,DNS托管模式只能单机验证,用API方式的好处能多个不同地方的angie可以独立管理ssl。如果没有通配符SSL需求直接用alpn方式就能满足需求.
网站配置和正常的一样:
upstream host_1 {
zone host_1 64k;
server 99.99.99.99:6680;
}
server {
listen 80;
server_name 99999.net *.99999.net;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen 443 quic;
http2 on;
http3 on;
server_name 99999.net *.99999.net;
status_zone host_1;
ssl_certificate $acme_cert_99999_net;
ssl_certificate_key $acme_cert_key_99999_net;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
gzip on;
gzip_proxied any;
gzip_vary on;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/rss+xml application/atom+xml image/svg+xml font/ttf font/otf application/vnd.ms-fontobject;
location / {
proxy_pass http://host_1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
}
}
最后,angie直接官方包直接支持js和lua安装后就能用,比原来的nginx和openresty更好用,具体更多细节查看官方文档https://cn.angie.software/angie/docs/installation/oss_packages/#oss-packages
另外域名太多的情况下可以考虑DCV域名指派方案(Domain Control Validation)。
年少轻狂的时候兜里掏不出富余的几百千来块钱,觉得几十百来万是小钱。
面对 现金流、税、房租、工资、社保、坏账、库存、设备、融资成本、折旧、养老、抚育、医疗、住房、婚嫁、人情世故各种问题后一个个都老实不语了;
之前那种不可一世不愿意总觉得和人有代沟的棱角也被磨平了,发现整个社会根本不会随便迁就自己, 也愿意主动迁就人了。
由于thinkphp只对Mysql有INSERT IGNORE方法,PostgreSQL是ON CONFLICT DO NOTHING方法,但是thinkphp orm一直没有支持,只能暂时在model用这个方法.
use think\facade\Db;
public static function insertIgnore(array $data, string $conflictTarget = null): int
{
$rawSql = static::fetchSql(true)->insert($data);
sql = "ON CONFLICT DO NOTHING";
if ($conflictTarget) {
$sql = "ON CONFLICT {$conflictTarget} DO NOTHING";
}
return Db::execute("{$rawSql} {$sql}");
}
前段时间看到老冯的公众号推送pgclone这玩意想搞来用一下 https://vonng.com/pg/pg-clone/
翻了下文档要求磁盘分区必须支持reflink才可以, 这就意味着ext4没法玩耍了, 必须XFS Btrfs ZFS分区格式才能玩.
public(公开):外部、内部、子类全通车
protected(受保护):家族内可用
private(私有):仅当前类可用
基础类class
abstract 抽象类,做基础架构、只能继承不能修改,extends后才能new实例化,做model之类的定义
final 最终完美类, 不能extends,可以new实例化
trait 代码复用,不能new初始化,只能class use引入
interface 接口类,不能被 new实例化,使用 implements 来实现接口, 一个类只能继承(extends)一个父类,但可以同时实现(implements)多个接口。
int 整数类型
string 字符串
float 浮点型 带小数点的
bool 布尔型 true或false
array 数组
object 对象
callable 可调用 只能是一个函数、闭包或者方法名
void 空
mixed 混合,任何类型(字符串、数字、数组、对象、甚至 null)
(int|string $id) 联合类型
function 函数
return 直接返回
用女人拍擦边性暗示的视频推广卖男装是我见过最愚蠢的精致营销。
买衣服要穿着合身和舒适, 其次才是好看。
即使我这种好色的老色批看这种营销内容都能感到满满的生理厌恶。
安装postgresql-18
apt install -y postgresql-common
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
install -d /usr/share/postgresql-common/pgdg
curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
apt update
apt install postgresql-18
主库配置
USER="replica"
PASSWORD=$(openssl rand -base64 24)
NETWOKR="0.0.0.0/0" //从库IP段
IP="1.1.1.1" #主库IP
#主库
cat>>/etc/postgresql/18/main/postgresql.conf<<EOF
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 1GB
archive_mode = off
#archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
EOF
#archive_mode归档模式很占空间
echo "host replication $USER $NETWOKR md5" >>/etc/postgresql/18/main/pg_hba.conf
# 创建用户(幂等)
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='$USER'" | grep -q 1 || \
sudo -u postgres psql -c "CREATE ROLE $USER WITH REPLICATION LOGIN PASSWORD '$PASSWORD';"
systemctl restart postgresql
echo "REPL $USER PASSWORD: $PASSWORD"
echo -e "\n\n从库快速导入备份bash shell:"
echo -e "USER=$USER\nPASSWORD=$PASSWORD"
echo "sudo -u postgres pg_basebackup -h $IP -U $USER -D /home/postgresql/18/main -P -R -X stream -v"
从库配置
IP="1.1.1.1" #主库IP
#rm -rf /var/lib/postgresql/18/main/*
cat>>/etc/postgresql/18/main/postgresql.conf<<EOF
listen_addresses = '*'
#recovery_min_apply_delay='24h' #延迟24小时同步
hot_standby = on
wal_keep_size = 2GB
max_wal_senders = 10
EOF
systemctl stop postgresql
mkdir /home/postgresql
chown -R postgres:postgres /home/postgresql
chmod 700 /home/postgresql
sudo -u postgres pg_basebackup -h $IP -U $USER -D /home/postgresql/18/main -P -R -X stream -v
systemctl start postgresql
建议修改/etc/postgresql/18/main/postgresql.conf的data_directory和max_connections参数
data_directory = '/home/postgresql/18/main'
#从库的设置小于主库的max_connections会无法启动
从库自动连接配置文件 /var/lib/postgresql/18/main/postgresql.auto.conf
检查核验配置
tail -n 100 /var/log/postgresql/postgresql-18-main.log
#验证主库
sudo -u postgres psql -c "SELECT client_addr,state FROM pg_stat_replication;"
#验证从库
sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
/etc/postgresql/18/main/conf.d/ 目录存放配置文件可以覆盖主配置
https://www.dnswatch.info/dns/dnslookup?la=en&host=164.210.103.in-addr.arpa&type=NS&submit=Resolve
两三年前刷过,老是重复出现看过的视频, 现在还是一点都没变。。。。。。
真是shi。。。。。。。。 shift
worker和swoole直接常驻内存运行抛弃fpm直接高效运行, 官方提供了现成的静态编译php文件,拿来直接可以运行,不用再自己吭哧吭哧再去编译,直接带上nginx就可以跑,如果将php打包成二进制文件会更简单。
几个相关项目发布地址
https://github.com/swoole/swoole-cli/releases
https://github.com/dixyes/phpmicro
https://github.com/crazywhalecc/static-php-cli
https://www.swoole.com/download
https://www.workerman.net/download
swoole-cli静态php
wget -O - https://github.com/swoole/swoole-cli/releases/download/v6.1.4.0/swoole-cli-v6.1.4-linux-x64.tar.xz | tar -xJ
install swoole-cli /usr/bin/swoole
workerman官方静态php
wget https://www.workerman.net/download/php/php-8.4-linux-x86_64.tar.gz| tar -xz
phpmicro可以打包php为二进制文件
swoole启动fpm
swoole-cli -P -h
# 运行 FPM
swoole-cli -P --fpm-config /opt/php-8.1/etc/php-fpm.conf -p /opt/php-8.1/var
# 关闭守护进程
swoole-cli -P --fpm-config /opt/php-8.1/etc/php-fpm.conf -p /opt/php-8.1/var -F
# 使用 root 账户启动
swoole-cli -P --fpm-config /opt/php-8.1/etc/php-fpm.conf -p /opt/php-8.1/var -F -R
https://github.com/stalwartlabs/stalwart/releases
https://github.com/mjl-/mox/releases
统计CPU
ps -u postgres -o %cpu | awk '{s+=$1} END {print "Postgres Total CPU: " s "%"}'
查看活跃查询
SELECT pid, now() - query_start AS duration, query, state FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC;
SELECT pid, now() - query_start AS duration, query, state FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC LIMIT 5;
查看连接IP和查询语句
SELECT pid, now() - query_start AS 执行时间, usename AS 用户名,
client_addr AS 连接IP, state AS 状态, query AS 查询语句
FROM pg_stat_activity WHERE
pid <> pg_backend_pid() ORDER BY 执行时间 DESC;
查看扫表
SELECT
relname AS 表名,
seq_scan AS 全表扫描次数,
seq_tup_read AS 全表扫描读取行数,
idx_scan AS 索引扫描次数,
idx_tup_fetch AS 索引提取行数
FROM pg_stat_user_tables
WHERE seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 10;
启用插件
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
重置自动增续ID
SELECT setval('tag_id_seq', (SELECT MAX(id) FROM tag));
给浏览器浏览器返回头
$file=decode($url);
header("X-Accel-Redirect: /privatefiles/$file");
nginx配置
location /privatefiles {
internal; #内部访问
alias /var/www/html/xaccel/restrictedfiles;
}
将文件名url加密, 然后接收解密,通过X-Accel-Redirect再转给nginx返回数据。
为什么要这么做? 一些文件路径在某些原因下不想暴露真实路径,又不通过程序再去读一遍问题直接转交个nginx响应。
转载自:https://dev.to/gbhorwood/nginx-serving-private-files-with-x-accel-redirect-57dl
DROP FUNCTION IF EXISTS public.table_msg(varchar) CASCADE;
DROP FUNCTION IF EXISTS public.table_msg(varchar, varchar) CASCADE;
DROP FUNCTION IF EXISTS public.pgsql_type(varchar) CASCADE;
DROP TYPE IF EXISTS public.tablestruct CASCADE;
CREATE OR REPLACE FUNCTION public.pgsql_type(a_type character varying) RETURNS character varying AS
$BODY$
DECLARE
v_type character varying;
BEGIN
CASE a_type
WHEN 'int8' THEN
v_type := 'bigint';
WHEN 'int4' THEN
v_type := 'integer';
WHEN 'int2' THEN
v_type := 'smallint';
WHEN 'bpchar' THEN
v_type := 'char';
ELSE
v_type := a_type;
END CASE;
RETURN v_type;
END;
$BODY$
LANGUAGE plpgsql;
-- 2. tablestruct 类型
CREATE TYPE public.tablestruct AS (
fields_key_name varchar(100),
fields_name varchar(200),
fields_type varchar(20),
fields_length bigint,
fields_not_null varchar(10),
fields_default varchar(500),
fields_comment varchar(1000)
);
-- 3. table_msg 函数(带 schema 参数)
CREATE OR REPLACE FUNCTION public.table_msg(a_schema_name varchar, a_table_name varchar)
RETURNS SETOF public.tablestruct AS
$body$
DECLARE
v_ret tablestruct;
v_oid oid;
v_sql varchar;
v_rec record;
v_key varchar;
BEGIN
-- 获取表 oid
SELECT c.oid INTO v_oid
FROM pg_class c
INNER JOIN pg_namespace n ON c.relnamespace = n.oid AND lower(n.nspname) = lower(a_schema_name)
WHERE c.relname = a_table_name;
IF NOT FOUND THEN
RETURN;
END IF;
-- 构造动态查询
v_sql := '
SELECT
a.attname AS fields_name,
a.attnum AS fields_index,
pgsql_type(t.typname::varchar) AS fields_type,
a.atttypmod - 4 AS fields_length,
CASE WHEN a.attnotnull THEN ''not null'' ELSE '''' END AS fields_not_null,
pg_get_expr(ad.adbin, ad.adrelid) AS fields_default,
d.description AS fields_comment
FROM pg_attribute a
INNER JOIN pg_class c ON a.attrelid = c.oid
INNER JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
LEFT JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = a.attnum
WHERE a.attnum > 0 AND a.attisdropped = false AND c.oid = ' || v_oid || '
ORDER BY a.attnum;
';
-- 遍历字段
FOR v_rec IN EXECUTE v_sql LOOP
v_ret.fields_name := v_rec.fields_name;
v_ret.fields_type := v_rec.fields_type;
IF v_rec.fields_length > 0 THEN
v_ret.fields_length := v_rec.fields_length;
ELSE
v_ret.fields_length := NULL;
END IF;
v_ret.fields_not_null := v_rec.fields_not_null;
v_ret.fields_default := v_rec.fields_default;
v_ret.fields_comment := v_rec.fields_comment;
SELECT constraint_name INTO v_key
FROM information_schema.key_column_usage
WHERE table_schema = a_schema_name
AND table_name = a_table_name
AND column_name = v_rec.fields_name;
IF FOUND THEN
v_ret.fields_key_name := v_key;
ELSE
v_ret.fields_key_name := '';
END IF;
RETURN NEXT v_ret;
END LOOP;
RETURN;
END;
$body$
LANGUAGE plpgsql VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;
COMMENT ON FUNCTION public.table_msg(a_schema_name varchar, a_table_name varchar) IS '获得表信息';
-- 4. table_msg 函数(简化版,只传 table_name)
CREATE OR REPLACE FUNCTION public.table_msg(a_table_name varchar)
RETURNS SETOF public.tablestruct AS
$body$
DECLARE
v_ret tablestruct;
BEGIN
FOR v_ret IN SELECT * FROM public.table_msg('public', a_table_name) LOOP
RETURN NEXT v_ret;
END LOOP;
RETURN;
END;
$body$
LANGUAGE plpgsql VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;
COMMENT ON FUNCTION public.table_msg(a_table_name varchar) IS '获得表信息';
- 1
- 2
- 3
- 4
- ...
- 68
- »