<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Ruosen]]></title><description><![CDATA[Be A Geek, Do The Right Thing;]]></description><link>http://ruosen.io/</link><generator>Ghost 0.7</generator><lastBuildDate>Sat, 14 Mar 2026 10:16:10 GMT</lastBuildDate><atom:link href="http://ruosen.io/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[用 acme.sh 自动续期 SSL 证书]]></title><description><![CDATA[<p>之前用腾讯云的免费 SSL 证书，每次快到期都得手动续，烦。今天换成了 acme.sh，彻底自动化了。</p>

<h2 id="">为什么换</h2>

<ul>
<li>腾讯云免费证书：手动续期，每季度都得操作一次</li>
<li>acme.sh：自动申请、自动续期、永久免费、不限次数</li>
</ul>

<h2 id="">方案选择</h2>

<p>acme.sh 支持两种验证方式：</p>

<ol>
<li><strong>DNS 验证</strong>：需要 DNS 服务商 API Key，支持通配符证书  </li>
<li><strong>HTTP 文件验证</strong>：在网站目录放验证文件，不需要 API Key</li>
</ol>

<p>我选了 HTTP 验证，不想给 API Key。</p>

<h2 id="">操作步骤</h2>

<h3 id="1">1. 创建验证目录</h3>

<pre><code class="language-bash">mkdir -p /var/www/</code></pre>]]></description><link>http://ruosen.io/157/</link><guid isPermaLink="false">199b6103-8cfc-4650-8411-afddcc1c0bcd</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Sat, 14 Mar 2026 08:46:42 GMT</pubDate><content:encoded><![CDATA[<p>之前用腾讯云的免费 SSL 证书，每次快到期都得手动续，烦。今天换成了 acme.sh，彻底自动化了。</p>

<h2 id="">为什么换</h2>

<ul>
<li>腾讯云免费证书：手动续期，每季度都得操作一次</li>
<li>acme.sh：自动申请、自动续期、永久免费、不限次数</li>
</ul>

<h2 id="">方案选择</h2>

<p>acme.sh 支持两种验证方式：</p>

<ol>
<li><strong>DNS 验证</strong>：需要 DNS 服务商 API Key，支持通配符证书  </li>
<li><strong>HTTP 文件验证</strong>：在网站目录放验证文件，不需要 API Key</li>
</ol>

<p>我选了 HTTP 验证，不想给 API Key。</p>

<h2 id="">操作步骤</h2>

<h3 id="1">1. 创建验证目录</h3>

<pre><code class="language-bash">mkdir -p /var/www/acme-challenge  
</code></pre>

<h3 id="2nginx">2. 配置 Nginx</h3>

<p>在 server block 里加一个优先级最高的 location，让 ACME 验证请求走静态文件：</p>

<pre><code class="language-nginx">server {  
    listen 80;
    server_name example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/acme-challenge;
    }

    location / {
        # 你原来的配置
        proxy_pass http://backend;
    }
}
</code></pre>

<p>443 端口的 server block 也加同样的 location。</p>

<p>测试配置并 reload：</p>

<pre><code class="language-bash">nginx -t &amp;&amp; nginx -s reload  
</code></pre>

<h3 id="3acmesh">3. 安装 acme.sh</h3>

<pre><code class="language-bash">curl https://get.acme.sh | sh -s email=your@email.com  
</code></pre>

<p>如果服务器 CA 证书太旧导致 curl SSL 验证失败，可以先下载到本地再传上去：</p>

<pre><code class="language-bash"># 本地
curl -L https://github.com/acmesh-official/acme.sh/archive/master.tar.gz -o acme.sh.tar.gz  
scp acme.sh.tar.gz root@server:/tmp/

# 服务器
cd /tmp &amp;&amp; tar xzf acme.sh.tar.gz  
cd acme.sh-master &amp;&amp; ./acme.sh --install -m your@email.com  
</code></pre>

<h3 id="4">4. 申请证书</h3>

<pre><code class="language-bash">~/.acme.sh/acme.sh --issue -d example.com -w /var/www/acme-challenge
</code></pre>

<p>第一次申请会自动注册账号（默认用 ZeroSSL，也可以指定 Let's Encrypt）。</p>

<h3 id="5nginx">5. 安装证书到 Nginx</h3>

<pre><code class="language-bash">~/.acme.sh/acme.sh --install-cert -d example.com \
    --key-file /etc/nginx/ssl/example.com/key.pem \
    --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
    --reloadcmd "nginx -s reload"
</code></pre>

<p>更新 Nginx 配置里的证书路径：</p>

<pre><code class="language-nginx">server {  
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com/key.pem;
    # ...
}
</code></pre>

<p>reload 一下：</p>

<pre><code class="language-bash">nginx -s reload  
</code></pre>

<h3 id="6">6. 确认自动续期</h3>

<p>acme.sh 安装时会自动加 cron job：</p>

<pre><code class="language-bash">crontab -l | grep acme  
# 输出类似：51 17 * * * "/root/.acme.sh"/acme.sh --cron ...
</code></pre>

<p>每天会自动检查证书，到期前 30 天自动续期并 reload Nginx。
须用 <code>^~</code> 前缀，否则可能被其他 location 规则覆盖
3. <strong>证书路径</strong>：建议统一放 <code>/etc/nginx/ssl/&lt;domain&gt;/</code>，方便管理</p>

<h2 id="">总结</h2>

<p>整个过程 10 分钟搞定，以后再也不用手动续证书了。acme.sh 支持几十家 DNS 服务商，如果需要通配符证书可以用 DNS 验证方式。</p>]]></content:encoded></item><item><title><![CDATA[Meta Quest 3 配对时踩的几个坑（注意事项）]]></title><description><![CDATA[<ol>
<li>quest设备在路由全局翻还不够，还得开启路由上的udp代理，以及机场需要支持udp，实测海豚湾的不行，Mono的可以  </li>
<li>手机上quest app配对VR时(输入验证码时)，手机不能是全局翻的状态，它的配对是本地wifi配对，不是蓝牙配对，需要扫描局域网。</li>
</ol>]]></description><link>http://ruosen.io/155/</link><guid isPermaLink="false">78d7e1e5-4903-4a9e-881a-0febb175f128</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Sat, 09 Dec 2023 06:49:06 GMT</pubDate><content:encoded><![CDATA[<ol>
<li>quest设备在路由全局翻还不够，还得开启路由上的udp代理，以及机场需要支持udp，实测海豚湾的不行，Mono的可以  </li>
<li>手机上quest app配对VR时(输入验证码时)，手机不能是全局翻的状态，它的配对是本地wifi配对，不是蓝牙配对，需要扫描局域网。</li>
</ol>]]></content:encoded></item><item><title><![CDATA[北京联通使用ODI猫棒+openwrt单线复用白嫖IPTV]]></title><description><![CDATA[<p>前两天听说北京联通的IPTV可以白嫖，rtp组播流可以直接看，于是折腾了下路由代理IPTV。</p>

<blockquote>
  <p>首先声明：这不是一个严谨的教程，而是折腾的经验，可能会有错误的理解，或者多余的操作，只为分享记录，互相借鉴。以下经验只适用于北京联通。</p>
</blockquote>

<p>用关键词<code>北京联通 openwrt IPTV</code>来搜索，网上已经有很多教程了，虽然每个教程的实际设备不太一样，大多都分为三步</p>

<ol>
<li>硬件配置：光猫桥接，或者分两条线连路由  </li>
<li>软件配置：igmpproxy igmpsnooping(igmp嗅探)等等设置  </li>
<li>防火墙设置：各种规则</li>
</ol>

<p>然后原文基本就说大功告成了，一开udpxy就能看电视。</p>

<p>然而自己实际去试，基本不可能一次跑通，多多少少由于设备不同，环境不同，哪里可能需要一些额外配置，下面说说我这种情况下(ODI猫棒DFP-34X-2C2)折腾的过程，和debug的方法。</p>

<p>ODI猫棒的固件列表：<a href="https://github.com/Anime4000/RTL960x/tree/main/Firmware/DFP-34X-2C2">https://github.com/Anime4000/RTL960x/tree/main/Firmware/DFP-34X-2C2</a></p>]]></description><link>http://ruosen.io/154/</link><guid isPermaLink="false">c7aa20c0-5122-4691-9a3b-578b94f75fd1</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Wed, 16 Aug 2023 17:44:04 GMT</pubDate><content:encoded><![CDATA[<p>前两天听说北京联通的IPTV可以白嫖，rtp组播流可以直接看，于是折腾了下路由代理IPTV。</p>

<blockquote>
  <p>首先声明：这不是一个严谨的教程，而是折腾的经验，可能会有错误的理解，或者多余的操作，只为分享记录，互相借鉴。以下经验只适用于北京联通。</p>
</blockquote>

<p>用关键词<code>北京联通 openwrt IPTV</code>来搜索，网上已经有很多教程了，虽然每个教程的实际设备不太一样，大多都分为三步</p>

<ol>
<li>硬件配置：光猫桥接，或者分两条线连路由  </li>
<li>软件配置：igmpproxy igmpsnooping(igmp嗅探)等等设置  </li>
<li>防火墙设置：各种规则</li>
</ol>

<p>然后原文基本就说大功告成了，一开udpxy就能看电视。</p>

<p>然而自己实际去试，基本不可能一次跑通，多多少少由于设备不同，环境不同，哪里可能需要一些额外配置，下面说说我这种情况下(ODI猫棒DFP-34X-2C2)折腾的过程，和debug的方法。</p>

<p>ODI猫棒的固件列表：<a href="https://github.com/Anime4000/RTL960x/tree/main/Firmware/DFP-34X-2C2">https://github.com/Anime4000/RTL960x/tree/main/Firmware/DFP-34X-2C2</a></p>

<p>一般网上北京联通的教程教你初次配置猫棒时，会让你先安装<code>Vlan_220414</code>固件，配置一个MAC的Mapping表，之后再刷<code>220923</code>固件桥接拨号。所以我现在使用的就是<code>220923</code></p>

<p>第一步：啥也不动，直接在有线连接的电脑上试一下PotPlayer能不能播放
<code>rtp://239.3.1.129:8008</code>这个链接，能看到画面，说明组播是通的，但是我之后配置udpxy怎么都代理不到这个组播流，很是灵异。为什么没配置IPTV任何东西就有组播流？不知道。为什么udpxy抓不到？不知道。一脸懵逼的开始折腾。</p>

<p>第二步：既然混在一起抓不到，那我单独把IPTV的子网拎出来看看是否可以代理到？
把<code>220923</code>固件中VLAN设置那个页面里的固定3961改成透传，然后在openwrt中拨号时，用eth0.3961这样的VLAN去拨号，再加一个接口用eth0.3964设置DHCP客户端，这样可以同时连公网并且拿到IPTV的内网IP，算是更近一步的进展。但是我用udpxy代理上游设置到这个接口，继续拿不到组播流。</p>

<p>此时开始了各种排查</p>

<ul>
<li>怀疑igmpproxy没起作用 (没起作用我也能收到组播流啊，忽略)</li>
<li>怀疑istore固件里没有接口的物理网络选项卡，以及igmp snooping的勾选。(通过命令行查看network配置发现默认有igmp snooping 1)</li>
<li>怀疑防火墙设置 (直接全开排除)</li>
<li>怀疑路由表有问题，(尝试修改路由表但是没有弄懂如何traceroute一个组播IP，不了了之)。</li>
</ul>

<p>如果在折腾中，你怀疑是否真的有rtp的组播流存在于内网，可以在任意直连内网网线的机器里(桥接的虚拟机不行)，试试tcpdump抓包</p>

<pre><code> tcpdump -T rtp -i eth2 udp portrange 8000-9000
</code></pre>

<p>这个命令是抓rtp协议的udp包，端口在8000-9000之间的，也就是联通组播端口的范围。PotPlayer一播放，内网就能抓到比如：</p>

<pre><code>00:52:40.598048 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2542 38265933 [|rtp]  
00:52:40.599834 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2543 38266109 [|rtp]  
00:52:40.600727 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2544 38266197 [|rtp]  
00:52:40.601553 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2545 38266285 [|rtp]  
00:52:40.604313 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2546 38266461 [|rtp]  
00:52:40.605154 IP 61.135.101.121.8060 &gt; 239.3.1.241.8000: udp/rtp 1316 c33  2547 38266548 [|rtp]  
</code></pre>

<p>第三步，刷固件换方案。</p>

<p>各种方法实验都不成功，最后找到了国外的一份<a href="https://hack-gpon.org/ont-odi-realtek-dfp-34x-2c2/">光猫wiki</a>里说，推荐用220916固件，因为VLAN相关设置是working的。试试换个思路，不在路由器配置，从猫入手。于是更新到这个固件。这个固件的UI有了很大变化，多了一堆可配置的地方，比如可以猫棒拨号，路由设定，组播VLAN设置（最关键的东西）。(我实际更新到的是0916的再下一个版本1209)</p>

<p>广域网可以按照下面的方式配置下：</p>

<p><img src="http://ruosen.io/content/images/2023/08/Screenshot-2023-08-17-013537.png" alt=""></p>

<p><img src="http://ruosen.io/content/images/2023/08/Screenshot-2023-08-17-013545.png" alt=""></p>

<p>其中<code>nas0_0</code>是internet拨号，<code>nas0_1</code>是IPTV内网。这样设置完之后，反而PC内网没有rtp组播流了。那么可以判断出，组播流如果不特殊设置，是无法透到下一个子网的，只能在相同内网内广播。这里需要一个igmpproxy但是猫棒里没有，于是准备找找固件里有没有现成的，还真找到了组播VLAN这个页面。</p>

<p><img src="http://ruosen.io/content/images/2023/08/Screenshot-2023-08-17-014234.png" alt=""></p>

<p>这里应该是配置透传组播信息的地方，先填上3964看看？没变化还是播不了。但是之前看别人教程说北京联通有个组播相关的VLAN是4000，填在这里看看，果真可以正常代理了。。</p>

<p>那么按我的理解这个组播数据流应该是从4000vlan下来的，但是为什么桥接3961/3964拨号时，还可以收到这个流？为什么其他人教程里没有填4000这回事还可以代理？全都不知道。糊里糊涂的就折腾好了，看来接下来还需要补一补网络底层知识。</p>

<p>我猜测第一步第二步时，组播数据带着vlanid4000来到路由器，而udpxy监听的只是跟3961 3964桥接的虚拟接口，所以抛弃了4000不认。但是数据proxy到lan时，抹掉了所有包的vlanid，因为下级没设置vlan，所以内网PC可以抓到流，而路由的软件不行。这个猜测还需要进一步验证。</p>]]></content:encoded></item><item><title><![CDATA[gitlab自动备份文件到群晖]]></title><description><![CDATA[<ul>
<li>把群晖smb挂载到gitlab机器</li>
<li>更改gitlab配置备份文件夹位置改到挂载目录</li>
<li>创建定时任务备份gitlab</li>
</ul>

<p>安装工具</p>

<pre><code>sudo apt-get install cifs-utils  
</code></pre>

<p>创建挂载点</p>

<pre><code>sudo mkdir /mnt/nas  
</code></pre>

<p>创建smb鉴权文件<code>.smbcredentials</code>，文件内容： </p>

<pre><code>username=$YOUR_USERNAME  
password=$YOUR_PASSWORD  
</code></pre>

<p>更改<code>/etc/fstab</code>文件，在最后一行添加</p>

<pre><code>//$YOUR_SMB_SERVER_ADDR/share /mnt/nas cifs credentials=/path/of/.smbcredentials,iocharset=utf8,dir_mode=0777,file_mode=0777,noperm 0 0</code></pre>]]></description><link>http://ruosen.io/153/</link><guid isPermaLink="false">5cc398f9-350a-4ced-a2c1-db586819b7b7</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Thu, 10 Aug 2023 11:40:48 GMT</pubDate><content:encoded><![CDATA[<ul>
<li>把群晖smb挂载到gitlab机器</li>
<li>更改gitlab配置备份文件夹位置改到挂载目录</li>
<li>创建定时任务备份gitlab</li>
</ul>

<p>安装工具</p>

<pre><code>sudo apt-get install cifs-utils  
</code></pre>

<p>创建挂载点</p>

<pre><code>sudo mkdir /mnt/nas  
</code></pre>

<p>创建smb鉴权文件<code>.smbcredentials</code>，文件内容： </p>

<pre><code>username=$YOUR_USERNAME  
password=$YOUR_PASSWORD  
</code></pre>

<p>更改<code>/etc/fstab</code>文件，在最后一行添加</p>

<pre><code>//$YOUR_SMB_SERVER_ADDR/share /mnt/nas cifs credentials=/path/of/.smbcredentials,iocharset=utf8,dir_mode=0777,file_mode=0777,noperm 0 0
</code></pre>

<p>其中<code>noperm</code>很重要，不检查文件权限，否则设置来设置去，总是不能777，gitlab备份总是Permission Denied</p>

<p>挂载目录, (如果之前挂的有问题，就先执行<code>sudo umount -a</code>再mount)</p>

<pre><code>sudo mount -a  
</code></pre>

<p>将挂在目录的命令<code>mount -a</code>添加到开启自动运行，注意添加在<code>exit 0</code>之前</p>

<pre><code>vim /etc/rc.local  
</code></pre>

<p>更改gitlab配置</p>

<pre><code>vim /etc/gitlab/gitlab.rb  
</code></pre>

<p>打开如下配置，酌情修改</p>

<pre><code>gitlab_rails['manage_backup_path'] = ture  
gitlab_rails['backup_path'] = "/mnt/nas"  
gitlab_rails['backup_keep_time'] = 604800  
</code></pre>

<p>让配置生效</p>

<pre><code>sudo gitlab-ctl reconfigure  
</code></pre>

<p>尝试手动备份，在挂载目录看到文件就代表成功</p>

<pre><code>sudo gitlab-rake gitlab:backup:create  
</code></pre>

<p>添加定时任务</p>

<pre><code>crontab -e  
</code></pre>

<p>增加一行, 每天凌晨4点备份</p>

<pre><code>0 4 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create  
</code></pre>]]></content:encoded></item><item><title><![CDATA[Gitlab旧版本迁移]]></title><description><![CDATA[<p>最近搞了个N305小主机准备玩玩虚拟机，顺便把gitlab从VPS迁过来，省一个机器钱。</p>

<p>最好的迁移方式是在兼容的最新系统里装一个旧版本的相同版本Gitlab，然后用备份恢复方式迁移。</p>

<h2 id="gitlabos">通过gitlab版本寻找适合的OS版本</h2>

<p>可以在已部署的gitlab网页中<code>/help</code>目录查看，或者命令行<code>sudo gitlab-rake gitlab:env:info</code>， 我这里是<code>8.9.2</code></p>

<p>在gitlab旧版本安装包页面 <a href="https://packages.gitlab.com/gitlab/gitlab-ce">https://packages.gitlab.com/gitlab/gitlab-ce</a> 中搜索8.9.2</p>

<p><img src="http://ruosen.io/content/images/2023/08/Screenshot-2023-08-10-174207.png" alt=""></p>

<p><code>Distro/Version</code>是发行版机器版本外号，这个还得查一下比如ubuntu16是xenial，
接下来就去OS官网寻找对应版本安装即可</p>

<h2 id="gitlab">新系统中安装旧版gitlab</h2>

<p>还是在gitlab旧版本安装包页面 <a href="https://packages.gitlab.com/gitlab/gitlab-ce">https://packages.gitlab.com/gitlab/gitlab-ce</a> 中下载对应OS版本的安装包(下载链接在点进去的右上角)</p>

<p>然后使用对应OS方法安装，参考<a href="https://docs.gitlab.com/ee/update/package/index.html#upgrade-using-a-manually-downloaded-package">https://docs.gitlab.com/</a></p>]]></description><link>http://ruosen.io/152/</link><guid isPermaLink="false">c8b79b41-7357-4ac4-97b5-26d66952cc60</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Thu, 10 Aug 2023 09:56:06 GMT</pubDate><content:encoded><![CDATA[<p>最近搞了个N305小主机准备玩玩虚拟机，顺便把gitlab从VPS迁过来，省一个机器钱。</p>

<p>最好的迁移方式是在兼容的最新系统里装一个旧版本的相同版本Gitlab，然后用备份恢复方式迁移。</p>

<h2 id="gitlabos">通过gitlab版本寻找适合的OS版本</h2>

<p>可以在已部署的gitlab网页中<code>/help</code>目录查看，或者命令行<code>sudo gitlab-rake gitlab:env:info</code>， 我这里是<code>8.9.2</code></p>

<p>在gitlab旧版本安装包页面 <a href="https://packages.gitlab.com/gitlab/gitlab-ce">https://packages.gitlab.com/gitlab/gitlab-ce</a> 中搜索8.9.2</p>

<p><img src="http://ruosen.io/content/images/2023/08/Screenshot-2023-08-10-174207.png" alt=""></p>

<p><code>Distro/Version</code>是发行版机器版本外号，这个还得查一下比如ubuntu16是xenial，
接下来就去OS官网寻找对应版本安装即可</p>

<h2 id="gitlab">新系统中安装旧版gitlab</h2>

<p>还是在gitlab旧版本安装包页面 <a href="https://packages.gitlab.com/gitlab/gitlab-ce">https://packages.gitlab.com/gitlab/gitlab-ce</a> 中下载对应OS版本的安装包(下载链接在点进去的右上角)</p>

<p>然后使用对应OS方法安装，参考<a href="https://docs.gitlab.com/ee/update/package/index.html#upgrade-using-a-manually-downloaded-package">https://docs.gitlab.com/ee/update/package/index.html#upgrade-using-a-manually-downloaded-package</a></p>

<p>比如Ubuntu使用 <code>sudo dpkg -i xxxx.deb</code></p>

<p>这样旧版gitlab就装好了 可以用<code>sudo gitlab-ctl status</code>看下启动正常不</p>

<h2 id="gitlab">备份待迁移的Gitlab数据，迁移到新机器恢复</h2>

<p>进入旧实例的网页<code>/help</code>中，寻找 <code>Administrator documentation</code>里面的<code>Raketasks</code>里面的<code>Backup restore</code>，查看备份和还原方法。(不同版本有微小区别，不能看最新的官方文档)</p>

<p>以8.9.2的deb安装包版本为例，现执行<code>sudo gitlab-rake gitlab:backup:create</code> 产出备份文件到 <code>/var/opt/gitlab/backups/</code></p>

<p>其他可能需要迁移的配置文件：</p>

<pre><code>/etc/gitlab/gitlab.rb 配置文件须备份
/var/opt/gitlab/nginx/conf nginx配置文件
/etc/postfix/main.cfpostfix 邮件配置备份
</code></pre>

<p>想办法用sftp或者scp把文件拷贝到新机器相同目录</p>

<p>在新机器执行</p>

<pre><code>sudo gitlab-rake gitlab:backup:restore BACKUP=123456789  
</code></pre>

<p>这里的123456789是备份文件的时间戳前缀，跟着提示两遍yes确认就顺利恢复了。</p>

<p>现在可以启动起来<code>sudo gitlab-ctl start</code>，看一下首页是否正常访问。</p>

<p>此时可能会发现首页正常，但是项目详情页500。</p>

<p>通过<code>sudo gitlab-ctl tail</code>可以查看实时日志</p>

<p>如果是 <code>openssl::cipher::ciphererror (bad decrypt):</code>的报错，其实是数据库加密的密钥没有迁移过来。
可以先将配置文件<code>/etc/gitlab/gitlab-secrets.json</code> 拷贝到新机器，然后执行下列命令</p>

<pre><code>sudo gitlab-rails runner "Project.where.not(import_url: nil).each { |p| p.import_data.destroy if p.import_data }"  
</code></pre>

<p>大功告成！</p>]]></content:encoded></item><item><title><![CDATA[新玩具]]></title><description><![CDATA[<p><img src="http://ruosen.io/content/images/2023/07/----_20230723010156-3.jpg" alt="R5S"></p>

<p>友善R5S，一个可以刷openwrt或者安卓TV的盒子</p>]]></description><link>http://ruosen.io/150/</link><guid isPermaLink="false">0b0ee8e9-80ed-4ef3-ac31-388ef69e3447</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Sat, 22 Jul 2023 19:56:01 GMT</pubDate><media:content url="http://ruosen.io/content/images/2023/07/----_20230723010156-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://ruosen.io/content/images/2023/07/----_20230723010156-2.jpg" alt="新玩具"><p><img src="http://ruosen.io/content/images/2023/07/----_20230723010156-3.jpg" alt="新玩具"></p>

<p>友善R5S，一个可以刷openwrt或者安卓TV的盒子</p>]]></content:encoded></item><item><title><![CDATA[一些随想]]></title><description><![CDATA[<h3 id="">世界</h3>

<p>数学是确定的
-> 物理建立在数学基础上，物理是确定的
-> 世界是物理的，世界是确定的
-> 真实世界是随机的，因为有意识存在
-> 意识不属于理论中的世界
-> 意识又存在，所以意识属于被加载进世界的
-> 世界有设计者，世界是虚拟的</p>

<h3 id="">意识</h3>

<p>意识的本质是记忆+判断</p>

<pre><code>let 记忆 = [];  
let 判断 = (事件,记忆) =&gt; 结果;  
while(事情){  
    记忆.push(判断(事情,记忆));
}
</code></pre>

<h3 id="">中国</h3>

<p>中国的本质还是封建</p>

<h3 id="">法律</h3>

<p>法律存在应该是避免未来发生某种事情，而不是对现在某种事情发生的惩罚/补偿。如果仅仅补偿损失，则犯罪平均期望获利大于0，无法阻止犯罪。</p>

<h3 id="">选举</h3>

<p>从历史来看，非民选政府一定会被革命推翻，二民选政府不会，</p>]]></description><link>http://ruosen.io/149/</link><guid isPermaLink="false">75ee2c3f-b7a6-46bd-9e0f-839e65c38a1f</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Thu, 23 Dec 2021 12:02:05 GMT</pubDate><content:encoded><![CDATA[<h3 id="">世界</h3>

<p>数学是确定的
-> 物理建立在数学基础上，物理是确定的
-> 世界是物理的，世界是确定的
-> 真实世界是随机的，因为有意识存在
-> 意识不属于理论中的世界
-> 意识又存在，所以意识属于被加载进世界的
-> 世界有设计者，世界是虚拟的</p>

<h3 id="">意识</h3>

<p>意识的本质是记忆+判断</p>

<pre><code>let 记忆 = [];  
let 判断 = (事件,记忆) =&gt; 结果;  
while(事情){  
    记忆.push(判断(事情,记忆));
}
</code></pre>

<h3 id="">中国</h3>

<p>中国的本质还是封建</p>

<h3 id="">法律</h3>

<p>法律存在应该是避免未来发生某种事情，而不是对现在某种事情发生的惩罚/补偿。如果仅仅补偿损失，则犯罪平均期望获利大于0，无法阻止犯罪。</p>

<h3 id="">选举</h3>

<p>从历史来看，非民选政府一定会被革命推翻，二民选政府不会，只需要把他选下去。从这个角度看，民选可更替政府是最终形态。</p>

<h3 id="">政治</h3>

<p>政治和写代码一样，初期简单粗暴不做项目管理，会让开发速度加倍，但终有一天需要重构。</p>

<p>如果一开始就上完整的项目管理流程，则会延误时机，从而竞争不过对手过早死亡。</p>

<p>民主(项目管理)是后期天赋，前期不用出，后期必加。</p>

<h3 id="">发展</h3>

<p>如果人类的设计者想要人类自发的科技进化(或者说自然选择出来的人类为什么会科技进化)。
是需要让(或者说因为)人类有动力，那就是私欲。资源有限，那么私欲就会产生竞争(战争)，战乱中总有一方更为先进，于是获胜一统天下，拉高世界科技水平，然后再因为私欲内部分裂，再次进入混乱，再次有人胜出，继续拉高科技水平。从而做到整个世界的进步。</p>]]></content:encoded></item><item><title><![CDATA[3080 3090显卡低负载boost导致反复自动启停的临时解决方案]]></title><description><![CDATA[<p>有人在nga发帖说遇到显卡低负载boost导致反复自动启动的问题
<a href="https://bbs.nga.cn/read.php?tid=23866974&amp;rand=264">https://bbs.nga.cn/read.php?tid=23866974&amp;rand=264</a></p>

<p>我用的影驰3090 gamer oc也遇到类似问题，各种软件设置的启停温度阈值都不起作用，经过观察后发现只要gpu clock boost就会启动风扇，哪怕温度只有30度。</p>

<p>分享一种临时解决方案</p>

<p>创建一个 nvdia inspector的快捷方式。参数 -setPStateLimit:0,4 </p>

<p>这个快捷方式执行后，显卡最高频率被限制在420mhz，并且启动游戏风扇也不会转了，但此时GPU性能很低，3090大约阉割到1060的样子，适合低负载操作，浏览网页看视频，普通游戏2K60p还是能带动的</p>

<p>恢复方式是 再建一个快捷方式，参数是 -setPStateLimit:0,0</p>

<p>至于为啥是4，我也不知道，我试出来的。。。</p>]]></description><link>http://ruosen.io/148/</link><guid isPermaLink="false">be8797a2-2c5d-4275-9e83-0771919878ab</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Sun, 24 Jan 2021 08:37:44 GMT</pubDate><content:encoded><![CDATA[<p>有人在nga发帖说遇到显卡低负载boost导致反复自动启动的问题
<a href="https://bbs.nga.cn/read.php?tid=23866974&amp;rand=264">https://bbs.nga.cn/read.php?tid=23866974&amp;rand=264</a></p>

<p>我用的影驰3090 gamer oc也遇到类似问题，各种软件设置的启停温度阈值都不起作用，经过观察后发现只要gpu clock boost就会启动风扇，哪怕温度只有30度。</p>

<p>分享一种临时解决方案</p>

<p>创建一个 nvdia inspector的快捷方式。参数 -setPStateLimit:0,4 </p>

<p>这个快捷方式执行后，显卡最高频率被限制在420mhz，并且启动游戏风扇也不会转了，但此时GPU性能很低，3090大约阉割到1060的样子，适合低负载操作，浏览网页看视频，普通游戏2K60p还是能带动的</p>

<p>恢复方式是 再建一个快捷方式，参数是 -setPStateLimit:0,0</p>

<p>至于为啥是4，我也不知道，我试出来的。。。</p>]]></content:encoded></item><item><title><![CDATA[解决育碧等游戏EasyAntiCheat反作弊插件误报“检测到调试工具”错误的方法]]></title><description><![CDATA[<p>管理员身份打开cmd，并执行</p>

<pre><code>bcdedit /debug off  
</code></pre>

<p>重启机器</p>]]></description><link>http://ruosen.io/147/</link><guid isPermaLink="false">ad95d462-6a34-43b1-8318-9915cca69a40</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Thu, 14 Jan 2021 15:11:59 GMT</pubDate><content:encoded><![CDATA[<p>管理员身份打开cmd，并执行</p>

<pre><code>bcdedit /debug off  
</code></pre>

<p>重启机器</p>]]></content:encoded></item><item><title><![CDATA[HTTPS 协议中，为什么需要第一步交换随机数]]></title><description><![CDATA[<p>最近在学习HTTPS</p>

<p><img src="https://user-gold-cdn.xitu.io/2018/5/21/1638197d98cf3281?imageslim" alt="https://user-gold-cdn.xitu.io/2018/5/21/1638197d98cf3281?imageslim"></p>

<p>按照流程：双方交换 random1 和 random2</p>

<p>客户端生成 random3 作为 pre master secret，并通过被签名的可靠公钥加密后传给 server，</p>

<p>这样双方都拿 random1 random2 random3 通过算法各自生成 master secret</p>

<p>在这里，只有 random3 是能够保证不被第三人知道的，为什么公开的 random1 和 random2 有存在的必要？为什么不直接生成 master secret 发过去？</p>

<p>查了查资料，这里是因为前向安全性。加入随机参数，使得：即使现在所有密钥都泄露了，历史消息也不会被破解。</p>

<p><a href="https://www.zhihu.com/question/45203206">https://www.zhihu.com/question/45203206</a></p>]]></description><link>http://ruosen.io/146/</link><guid isPermaLink="false">fd29ec03-99db-49ca-bf65-79451dc32216</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Fri, 15 Feb 2019 06:59:08 GMT</pubDate><content:encoded><![CDATA[<p>最近在学习HTTPS</p>

<p><img src="https://user-gold-cdn.xitu.io/2018/5/21/1638197d98cf3281?imageslim" alt="https://user-gold-cdn.xitu.io/2018/5/21/1638197d98cf3281?imageslim"></p>

<p>按照流程：双方交换 random1 和 random2</p>

<p>客户端生成 random3 作为 pre master secret，并通过被签名的可靠公钥加密后传给 server，</p>

<p>这样双方都拿 random1 random2 random3 通过算法各自生成 master secret</p>

<p>在这里，只有 random3 是能够保证不被第三人知道的，为什么公开的 random1 和 random2 有存在的必要？为什么不直接生成 master secret 发过去？</p>

<p>查了查资料，这里是因为前向安全性。加入随机参数，使得：即使现在所有密钥都泄露了，历史消息也不会被破解。</p>

<p><a href="https://www.zhihu.com/question/45203206">https://www.zhihu.com/question/45203206</a></p>]]></content:encoded></item><item><title><![CDATA[部分安卓机默认字体大小改变导致webview内rem计算错误]]></title><description><![CDATA[<pre><code>function adapt(){  
        var d = window.document.createElement('div');
        d.style.width = '1rem';
        d.style.display = "none";
        var head = window.document.getElementsByTagName('head')[0];
        head.appendChild(d);
        var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'));
        return defaultFontSize
    };
</code></pre>

<p>获取实际根字体大小后再计算比例差值</p>

<pre><code>pxOneRem = pxOneRem * 16 / adapt();  
docEl.style.fontSize = pxOneRem + 'px'  
</code></pre>]]></description><link>http://ruosen.io/145/</link><guid isPermaLink="false">137ecbd9-0088-4cbd-b9b3-2f45e4d6bb3a</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Tue, 17 Jul 2018 09:27:43 GMT</pubDate><content:encoded><![CDATA[<pre><code>function adapt(){  
        var d = window.document.createElement('div');
        d.style.width = '1rem';
        d.style.display = "none";
        var head = window.document.getElementsByTagName('head')[0];
        head.appendChild(d);
        var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'));
        return defaultFontSize
    };
</code></pre>

<p>获取实际根字体大小后再计算比例差值</p>

<pre><code>pxOneRem = pxOneRem * 16 / adapt();  
docEl.style.fontSize = pxOneRem + 'px'  
</code></pre>]]></content:encoded></item><item><title><![CDATA[我，不同意]]></title><description><![CDATA[<p><img src="http://ww1.sinaimg.cn/large/3fab340fly1fou2efas0qj20pd0kaq5e.jpg" alt="http://ww1.sinaimg.cn/large/3fab340fly1fou2efas0qj20pd0kaq5e.jpg">
不同意</p>]]></description><link>http://ruosen.io/144/</link><guid isPermaLink="false">e7a37c10-445f-474f-b313-c46f03449879</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Mon, 26 Feb 2018 11:20:27 GMT</pubDate><content:encoded><![CDATA[<p><img src="http://ww1.sinaimg.cn/large/3fab340fly1fou2efas0qj20pd0kaq5e.jpg" alt="http://ww1.sinaimg.cn/large/3fab340fly1fou2efas0qj20pd0kaq5e.jpg">
不同意</p>]]></content:encoded></item><item><title><![CDATA[五子棋小游戏]]></title><description><![CDATA[<p>看到一个帖子说腾讯前端的面试题是让写一个五子棋小游戏</p>

<blockquote>
  <ul>
  <li>实现胜负判断，并给出赢棋提示。</li>
  <li>任意一方赢棋，锁定棋盘。</li>
  <li>尽可能考虑游戏的扩展性，界面可用 DOM/ Canvas 实现，并且切换实现方式代价最小。</li>
  <li>实现悔棋和撤销悔棋功能。</li>
  <li>人机对战部分可选。</li>
  </ul>
</blockquote>

<p>挺有意思的，尝试自己写一个。</p>

<p>代码:<a href="https://github.com/chairuosen/my-five">https://github.com/chairuosen/my-five</a></p>

<p>demo:<a href="http://demo.ruosen.io/my-five/dist/">http://demo.ruosen.io/my-five/dist/</a></p>

<h3 id="">思路</h3>

<p>首先，要求渲染层可替换，那么逻辑代码就一定要高度抽象，仅对数据操作，然后每一次变动由数据渲染出画面，应该对外提供一个五子棋类，提供api查询棋盘状态，和下棋，撤销，重置等动作。然后可以注册update事件监听来更新渲染。</p>

<p>类 棋子: 状态[未分配，黑，白] 重置方法</p>

<p>因为要点击空白部分来放置棋子，与其判断点击位置来放置棋子数据，不如一开始就铺满棋子只是不显示，</p>]]></description><link>http://ruosen.io/143/</link><guid isPermaLink="false">be733b6e-ed99-41f0-b3bb-9cce5ae74f28</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Tue, 20 Jun 2017 15:34:14 GMT</pubDate><content:encoded><![CDATA[<p>看到一个帖子说腾讯前端的面试题是让写一个五子棋小游戏</p>

<blockquote>
  <ul>
  <li>实现胜负判断，并给出赢棋提示。</li>
  <li>任意一方赢棋，锁定棋盘。</li>
  <li>尽可能考虑游戏的扩展性，界面可用 DOM/ Canvas 实现，并且切换实现方式代价最小。</li>
  <li>实现悔棋和撤销悔棋功能。</li>
  <li>人机对战部分可选。</li>
  </ul>
</blockquote>

<p>挺有意思的，尝试自己写一个。</p>

<p>代码:<a href="https://github.com/chairuosen/my-five">https://github.com/chairuosen/my-five</a></p>

<p>demo:<a href="http://demo.ruosen.io/my-five/dist/">http://demo.ruosen.io/my-five/dist/</a></p>

<h3 id="">思路</h3>

<p>首先，要求渲染层可替换，那么逻辑代码就一定要高度抽象，仅对数据操作，然后每一次变动由数据渲染出画面，应该对外提供一个五子棋类，提供api查询棋盘状态，和下棋，撤销，重置等动作。然后可以注册update事件监听来更新渲染。</p>

<p>类 棋子: 状态[未分配，黑，白] 重置方法</p>

<p>因为要点击空白部分来放置棋子，与其判断点击位置来放置棋子数据，不如一开始就铺满棋子只是不显示，点击事件就放在隐形棋子身上。</p>

<p>类 棋盘: 宽度，高度，二维矩阵[[棋子...]...] 赢棋检查 重置方法</p>

<p>类 玩家</p>

<p>类 五子棋: 棋盘 玩家 历史记录  重置方法</p>

<p>实现起来还是挺简单的，有一点复杂的就是赢棋检查这里，没想到什么高效的算法，遍历棋盘成本稍高，所以加了一层判断缓存。当遍历到某一节点1时，发现某一方向[1,2,3..]n星连珠但组不成5星时，把这n个节点在这一方向的结果都在缓存置为false，下次遍历到2，3，4时不用计算。</p>

<p>//todo AI</p>]]></content:encoded></item><item><title><![CDATA[js 实现 immutable]]></title><description><![CDATA[<p>想到一种利用Proxy实现immutable的方法，非常简单，不知道为什么其他库那么大？</p>

<pre><code class="language-javascript">function immutable(source) {  
    return new Proxy(source,{
        get:function(target,key){
            try{
                return immutable(target[key]);
            }catch(e){
                return target[key];
            }
        },set:function(){}
    });
}
</code></pre>

<p><a href="https://github.com/chairuosen/my-immutable-js">https://github.com/chairuosen/my-immutable-js</a></p>]]></description><link>http://ruosen.io/142/</link><guid isPermaLink="false">19e1b480-c1e6-4e37-a3b4-7153520cb911</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Mon, 20 Feb 2017 08:22:43 GMT</pubDate><content:encoded><![CDATA[<p>想到一种利用Proxy实现immutable的方法，非常简单，不知道为什么其他库那么大？</p>

<pre><code class="language-javascript">function immutable(source) {  
    return new Proxy(source,{
        get:function(target,key){
            try{
                return immutable(target[key]);
            }catch(e){
                return target[key];
            }
        },set:function(){}
    });
}
</code></pre>

<p><a href="https://github.com/chairuosen/my-immutable-js">https://github.com/chairuosen/my-immutable-js</a></p>]]></content:encoded></item><item><title><![CDATA[群晖笔记]]></title><description><![CDATA[<ul>
<li>ssh免密配完需要 <code>chmod 755 ~</code>，默认居然是777</li>
<li>配sudo免密单个用户不成功，最后把admin组改成NOPASSWD才可以，不知为何</li>
<li>局域网文件共享。windows需要开启网络发现。匿名共享需要开启群晖guest用户，guest用户在控制面板>用户>高级里面先去掉强制密码检查才能设置无密码。</li>
</ul>]]></description><link>http://ruosen.io/141/</link><guid isPermaLink="false">b676d73d-ff48-41dd-b43f-4982a7cbac4e</guid><dc:creator><![CDATA[Ruosen]]></dc:creator><pubDate>Sat, 23 Jul 2016 17:28:13 GMT</pubDate><content:encoded><![CDATA[<ul>
<li>ssh免密配完需要 <code>chmod 755 ~</code>，默认居然是777</li>
<li>配sudo免密单个用户不成功，最后把admin组改成NOPASSWD才可以，不知为何</li>
<li>局域网文件共享。windows需要开启网络发现。匿名共享需要开启群晖guest用户，guest用户在控制面板>用户>高级里面先去掉强制密码检查才能设置无密码。</li>
</ul>]]></content:encoded></item></channel></rss>