-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1604 lines (1604 loc) · 236 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>使用华硕AC68u做局域网透明代理</title>
<url>/p/asus-ac68u-shadowsocks.html</url>
<content><![CDATA[<h4 id="注意事项">注意事项</h4>
<ol>
<li>本文描述内容基于华硕固件384版本,</li>
<li>路由界面的固件升级不支持第三方固件</li>
<li>华硕官方梅林 不带软件中心页面</li>
<li>如果需要持久化程序,路由器需开启jffs分区 因其他分区在路由重启的时候会进行清理,不能持久化,而jffs分区是不会的(可在管理界面开启)</li>
</ol>
<h4 id="尝试且失败">尝试且失败</h4>
<h6 id="1-dnsmasq-ss-redir-ss-tunnel-ipset4-iptable">1. dnsmasq + ss-redir + ss-tunnel + ipset4 + iptable</h6>
<ul>
<li><a class="link" href="http://www.asussmart.com/smart/36.html" >开启ssh<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 系统设置里开启ssh</li>
<li><a class="link" href="https://www.snbforums.com/threads/how-to-install-entware-to-jffs-without-usb-flashdrive.39700/" >如何安装软件包管理器opkg 不使用外置U盘<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 原理主要是改安装文件/usr/sbin/entware-setup.sh 的一个文件系统格式验证</li>
</ul>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">Copy the file /usr/sbin/entware-setup.sh to jffs and then modify the PART_TYPES variables on line 23 and 27 to include the jffs partition</span><br><span class="line"></span><br><span class="line">Code:</span><br><span class="line">case $(uname -m) in</span><br><span class="line"> armv7l)</span><br><span class="line"> PART_TYPES='ext2|ext3|ext4|jffs2'</span><br><span class="line"> INST_URL='http://pkg.entware.net/binaries/armv7/installer/entware_install.sh'</span><br><span class="line"> ;;</span><br><span class="line"> mips)</span><br><span class="line"> PART_TYPES='ext2|ext3|jffs2'</span><br><span class="line"> INST_URL='http://pkg.entware.net/binaries/mipsel/installer/installer.sh'</span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> echo "This is unsupported platform, sorry."</span><br><span class="line"> ;;</span><br><span class="line">esac</span><br></pre></td></tr></table></figure></div>
<ul>
<li><a class="link" href="https://w2x.me/2018/09/20/ASUS-66u-%E6%90%AD%E5%BB%BA%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86/" >参考文章<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 按文章操作后路由器进入一直重启状态,原因未知 <strong>failed</strong></li>
</ul>
<h6 id="2-救援模式刷advancedtomato-参考文章">2. 救援模式刷advancedtomato <a class="link" href="https://tedstechshack.com/2015/10/26/how-to-flash-advancedtomato-firmware-on-an-asus-rt-ac68u-router/" >参考文章<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h6>
<ul>
<li>刷完系统直接进入救援模式(原因未知) <strong>failed</strong></li>
</ul>
<h4 id="最终方案-koolshare-merlin">最终方案 koolshare-merlin</h4>
<ol>
<li>通过<a class="link" href="http://52asus.com/thread-34-1-2.html" >救援模式<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>刷koolshare-merlin</li>
</ol>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">Step1.安装程式,可以去ASUS官网下载公用程序,然后安装,如RT-AC68U可以在此链接下载 http://www.asus.com.cn/Networking/RTAC68U/#support</span><br><span class="line">Step2.让Router进入救援模式:此操作很关键,先关机,再按住路由器Reset 按钮不放的同时接通路由器电源,直到看到电源灯慢闪时放开Reset按钮.</span><br><span class="line">Step3.电脑接到路由器的Lan 端口,且需要固定IP地址(192.168.1.xxx)</span><br><span class="line"></span><br><span class="line">Step4.开启Firmware Restoration程式(如下图),点击“Browse”button 选择固件存放路径后点击“Upload”button.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Step5.等待1~3分钟完成,按照提示重启路由器,最好再通过再用Reset按钮使路由器恢复出.</span><br><span class="line"></span><br><span class="line">//Step2 是进入救援模式 其他步骤为通过华硕官方程序(不支持macOs)刷固件</span><br><span class="line">//当进入救援模式后,访问路由地址192.168.x.x, 会进入miniWeb 界面,在界面中也可以刷固件,只是miniweb没有程序好用?偶尔打不开,而程序是一直ok的</span><br></pre></td></tr></table></figure></div>
<ol start="2">
<li><a class="link" href="https://firmware.koolshare.cn/Koolshare_Merlin_Legacy_380/ASUS/RT-AC68U/X7.9/" >固件地址<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
<li>刷完后路由界面就增加软件中心了,这时候需完成 ->开启jffs->更新软件中心</li>
<li>当前固件版本不内置ss在软件列表中,可通过<a class="link" href="https://www.codeidc.com/archives/99" >离线安装<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>模式安装 //<a class="link" href="https://raw.githubusercontent.com/hq450/fancyss_history_package/master/fancyss_arm/shadowsocks_4.0.5.tar.gz" >软件包<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ol>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">cd /tmp</span><br><span class="line">wget --no-check-certificate https://github.com/hq450/fancyss/blob/master/fancyss_arm/shadowsocks.tar.gz</span><br><span class="line">tar -zxvf /tmp/shadowsocks.tar.gz</span><br><span class="line">chmod +x /tmp/shadowsocks/install.sh</span><br><span class="line">sh /tmp/shadowsocks/install.sh</span><br><span class="line"></span><br><span class="line"># 或者下载 shadowsocks.tar.gz 后在软件中心页离线安装中上传</span><br></pre></td></tr></table></figure></div>
<ol start="5">
<li>之后就是配置ss,配置完开启就ok了</li>
</ol>
<h6 id="备注-koolshare-merlin-为闭源固件,问题不是很大,但是毕竟未开源,有时间再折腾其他固件">备注:koolshare-merlin 为闭源固件,问题不是很大,但是毕竟未开源,有时间再折腾其他固件</h6>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>linux</tag>
<tag>shadowsocks</tag>
<tag>example</tag>
</tags>
</entry>
<entry>
<title>Hexo 博客搭建</title>
<url>/p/build-blog.html</url>
<content><![CDATA[<h1>Hexo 博客搭建</h1>
<h2 id="What-is-Hexo">What is Hexo?</h2>
<p>Hexo is a fast, simple and powerful blog framework. You write posts in Markdown (or other markup languages) and Hexo<br>
generates static files with a beautiful theme in seconds.</p>
<p>(copy from <a class="link" href="https://hexo.io/docs/" >https://hexo.io/docs/<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>)</p>
<ul>
<li>hexo 是一个博客搭建框架</li>
<li>hexo 自带主题比较简单,通常会选择找一个更适合的主题</li>
</ul>
<h2 id="Hexo-环境">Hexo 环境</h2>
<ul>
<li>nodejs</li>
</ul>
<p>nodejs 安装推荐使用<a class="link" href="https://github.com/nvm-sh/nvm" >nvm<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 支持本地多版本环境切换</p>
<ul>
<li><a class="link" href="https://hexo.io/docs/#Install-Hexo" >hexo-cli<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ul>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure></div>
<h2 id="Hexo-Setup">Hexo Setup</h2>
<p>Once Hexo is installed, run the following commands to initialize Hexo in the target <folder>.</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">hexo init <folder></span><br><span class="line"><span class="built_in">cd</span> <folder></span><br><span class="line">npm install</span><br></pre></td></tr></table></figure></div>
<p>Once initialized, here’s what your project folder will look like:</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">.</span><br><span class="line">├── _config.yml</span><br><span class="line">├── package.json</span><br><span class="line">├── scaffolds</span><br><span class="line">├── <span class="built_in">source</span></span><br><span class="line">| ├── _drafts</span><br><span class="line">| └── _posts</span><br><span class="line">└── themes</span><br></pre></td></tr></table></figure></div>
<h3 id="config-yml">_config.yml</h3>
<p>Site configuration file. You can configure most settings here.</p>
<h3 id="package-json">package.json</h3>
<p>Application data. The EJS, Stylus and Markdown renderers are installed by default. If you want, you can uninstall them<br>
later.</p>
<p>package.json</p>
<div class="code-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"hexo-site"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"version"</span><span class="punctuation">:</span> <span class="string">"0.0.0"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"private"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"version"</span><span class="punctuation">:</span> <span class="string">""</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"dependencies"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"hexo"</span><span class="punctuation">:</span> <span class="string">"^3.8.0"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-generator-archive"</span><span class="punctuation">:</span> <span class="string">"^0.1.5"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-generator-category"</span><span class="punctuation">:</span> <span class="string">"^0.1.3"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-generator-index"</span><span class="punctuation">:</span> <span class="string">"^0.2.1"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-generator-tag"</span><span class="punctuation">:</span> <span class="string">"^0.2.0"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-renderer-ejs"</span><span class="punctuation">:</span> <span class="string">"^0.3.1"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-renderer-stylus"</span><span class="punctuation">:</span> <span class="string">"^0.3.3"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-renderer-marked"</span><span class="punctuation">:</span> <span class="string">"^0.3.2"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"hexo-server"</span><span class="punctuation">:</span> <span class="string">"^0.3.3"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure></div>
<p>copy from (<a class="link" href="https://hexo.io/docs/setup" >https://hexo.io/docs/setup<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>)</p>
<h2 id="Hexo-主题安装">Hexo 主题安装</h2>
<p>本站点使用 <a class="link" href="https://redefine-docs.evanluo.top/" >redefine 主题<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 当前安装版本 v0.4.5</p>
<ul>
<li>简洁、五脏俱全</li>
</ul>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> your-hexo-site</span><br><span class="line">npm install hexo-theme-redefine@latest</span><br></pre></td></tr></table></figure></div>
<h3 id="安装完成后,在-Hexo-配置文件中将-theme-设置为-Redefine。">安装完成后,在 Hexo 配置文件中将 theme 设置为 Redefine。</h3>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># _config.yml</span></span><br><span class="line">theme: redefine</span><br></pre></td></tr></table></figure></div>
<p>顺便删除自带主题</p>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="string">rm</span> <span class="string">_config.landscape.yml</span></span><br><span class="line"></span><br><span class="line"><span class="string">npm</span> <span class="string">remove</span> <span class="string">hexo-theme-landscape</span></span><br></pre></td></tr></table></figure></div>
<p>这个主题基本是开箱即用,默认的配置就挺好的,可以修改一些偏个人信息的部分</p>
<h3 id="修改配置">修改配置</h3>
<p>首先从主题文件中复制默认配置到项目根目录</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cp</span> node_modules/hexo-theme-redefine/_config.yml _config.redefine.yml</span><br></pre></td></tr></table></figure></div>
<p>修改配置中基础信息部分 _config.redefine.yml</p>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 基础信息</span></span><br><span class="line"><span class="attr">base_info:</span></span><br><span class="line"> <span class="attr">title:</span> <span class="string">Attson</span> <span class="string">Thinking</span> <span class="comment"># Site title</span></span><br><span class="line"> <span class="attr">author:</span> <span class="string">Attson</span> <span class="comment"># Author name</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">https://attson.github.io</span> <span class="comment"># Site url</span></span><br><span class="line"> <span class="comment"># Logo image (You can use local image, image external link or don’t fill)</span></span><br><span class="line"> <span class="attr">logo_img:</span> <span class="comment"># logo image on the left of the navigation bar</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 作者头像和网站图标部分</span></span><br><span class="line"><span class="attr">style:</span></span><br><span class="line"> <span class="comment"># 说明: images 路径 -> 在source/images </span></span><br><span class="line"> <span class="comment"># <= v0.4.5 主题内置文件 images/(avatar.svg loading.svg logo.svg logo.webp), 请避开这些文件命名</span></span><br><span class="line"> <span class="attr">avatar:</span> <span class="string">/images/my_avatar.svg</span> <span class="comment"># avatar of the author</span></span><br><span class="line"> <span class="comment"># Favicon (You can use local image or image external link)</span></span><br><span class="line"> <span class="attr">favicon:</span> <span class="string">/images/my_logo.svg</span> <span class="comment"># favicon of the site</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">first_screen:</span></span><br><span class="line"> <span class="attr">background_image:</span></span><br><span class="line"> <span class="attr">light:</span> <span class="string">/images/background.jpeg</span> <span class="comment"># background image of the first screen, use relative path or external link (if your website is in subdirectory, use external link)</span></span><br><span class="line"> <span class="attr">dark:</span> <span class="string">/images/background.jpeg</span> <span class="comment"># background image of the first screen, use relative path or external link (if your website is in subdirectory, use external link)</span></span><br><span class="line"> <span class="comment"># 网站首页一段文案,可以改成自己喜欢的</span></span><br><span class="line"> <span class="attr">description:</span> <span class="string">可怕的不是死亡,而是你从未真正活过</span> <span class="comment"># the title in the middle of the first screen. HTML supported (e.g. svg html code of your logo)</span></span><br><span class="line"><span class="comment"># 菜单部分</span></span><br><span class="line"><span class="attr">menu:</span></span><br><span class="line"> <span class="comment"># 增加 tags 页</span></span><br><span class="line"> <span class="attr">Tags:</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/tags</span></span><br></pre></td></tr></table></figure></div>
<h2 id="部署-github-io">部署 <a class="link" href="http://github.io" >github.io<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></h2>
<ul>
<li>本站点为了区分源文件和静态站点文件,采用两个仓库来维护博客</li>
<li>私有仓库 attson-blog 用于放源文件</li>
<li>公开仓库 <a href="http://attson.github.io">attson.github.io</a> 用于放build后的静态文件, GitHub pages</li>
</ul>
<p>注意: 默认情况 <code>hexo generate</code> 是忽略过程中的异常,在自动化构建脚本中,忽略异常可能会导致部署了有bug的博客。增加 -b 参数</p>
<div class="code-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"scripts"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"build"</span><span class="punctuation">:</span> <span class="string">"hexo generate -b"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"clean"</span><span class="punctuation">:</span> <span class="string">"hexo clean"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"deploy"</span><span class="punctuation">:</span> <span class="string">"hexo deploy"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"server"</span><span class="punctuation">:</span> <span class="string">"hexo server"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure></div>
<h3 id="自动化部署使用-github-workflows">自动化部署使用 github workflows</h3>
<ul>
<li>使用 github workflows 好处是不需要再依赖其他deploy插件</li>
</ul>
<p>增加文件 .github/workflows/deploy.yml</p>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 文件内容基本来自 https://hexo.io/docs/github-pages</span></span><br><span class="line"><span class="comment"># 统一使用v3 版本 v2 部分功能已弃用</span></span><br><span class="line"></span><br><span class="line"><span class="attr">name:</span> <span class="string">Deploy</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line"> <span class="attr">push:</span></span><br><span class="line"> <span class="attr">branches:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">master</span> <span class="comment"># default branch</span></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line"> <span class="attr">pages:</span></span><br><span class="line"> <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line"> <span class="attr">steps:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">actions/checkout@v3</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">token:</span> <span class="string">${{</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">}}</span></span><br><span class="line"> <span class="comment"># If your repository depends on submodule, please see: https://github.com/actions/checkout</span></span><br><span class="line"> <span class="attr">submodules:</span> <span class="string">recursive</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Use</span> <span class="string">Node.js</span> <span class="number">16.</span><span class="string">x</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/setup-node@v3</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">node-version:</span> <span class="string">'16'</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Cache</span> <span class="string">NPM</span> <span class="string">dependencies</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/cache@v3</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">node_modules</span></span><br><span class="line"> <span class="attr">key:</span> <span class="string">${{</span> <span class="string">runner.OS</span> <span class="string">}}-npm-cache</span></span><br><span class="line"> <span class="attr">restore-keys:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> ${{ runner.OS }}-npm-cache</span></span><br><span class="line"><span class="string"></span> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Install</span> <span class="string">Dependencies</span></span><br><span class="line"> <span class="attr">run:</span> <span class="string">npm</span> <span class="string">install</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Build</span></span><br><span class="line"> <span class="attr">run:</span> <span class="string">npm</span> <span class="string">run</span> <span class="string">build</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Deploy</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">peaceiris/actions-gh-pages@v3</span></span><br><span class="line"> <span class="comment"># 配置说明 https://github.com/peaceiris/actions-gh-pages</span></span><br><span class="line"> <span class="comment"># 修改最后部署的部分 (如不区分两个仓库,则无需修改)</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">deploy_key:</span> <span class="string">${{</span> <span class="string">secrets.DEPLOY_GITHUB_IO_SECRECT</span> <span class="string">}}</span></span><br><span class="line"> <span class="attr">external_repository:</span> <span class="string">"attson/attson.github.io"</span></span><br><span class="line"> <span class="attr">publish_branch:</span> <span class="string">master</span></span><br><span class="line"> <span class="attr">publish_dir:</span> <span class="string">./public</span></span><br><span class="line"> <span class="comment"># 修改 commit 信息,默认是 attson/attson-blog@30438be</span></span><br><span class="line"> <span class="attr">full_commit_message:</span> <span class="string">${{</span> <span class="string">github.event.head_commit.message</span> <span class="string">}}</span></span><br></pre></td></tr></table></figure></div>
<h4 id="其中-deploy-key-需要在两个仓库分别设置-ssh-私钥和公钥">其中 deploy_key 需要在两个仓库分别设置 ssh 私钥和公钥</h4>
<p>生成keys</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">ssh-keygen -t rsa -b 4096 -C <span class="string">"<your email address>"</span> -f <span class="string">"attson.github.io"</span> -N <span class="string">""</span></span><br></pre></td></tr></table></figure></div>
<h4 id="在公开仓库-attson-github-io-添加-deploy-key,用于支持部署(公钥)">在公开仓库 <a href="http://attson.github.io">attson.github.io</a> 添加 deploy key,用于支持部署(公钥)</h4>
<ul>
<li>Title 任意</li>
<li>注意勾选 write access</li>
</ul>
<img
lazyload
src="/images/loading.svg"
data-src="/p/build-blog/deploy.png"
class="" title="deploy.png"
>
<h4 id="在私有仓库-attson-blog-添加-secrets-key,用于访问-attson-github-io(私钥)">在私有仓库 attson-blog 添加 secrets key,用于访问 <a href="http://attson.github.io">attson.github.io</a>(私钥)</h4>
<ul>
<li>title 需与 .github/workflows/deploy.yml 中 deploy_key 一致 DEPLOY_GITHUB_IO_SECRECT</li>
</ul>
<img
lazyload
src="/images/loading.svg"
data-src="/p/build-blog/secret.png"
class="" title="secret.png"
>
<h4 id="git-commit-git-push">git commit && git push</h4>
<ul>
<li>配置完以上后,就可以直接提交代码到 源文件仓库了,github 的 workflow 会在提交之后自动触发</li>
<li>在 Actions 处可以看到 workflow 情况</li>
</ul>
<img
lazyload
src="/images/loading.svg"
data-src="/p/build-blog/action.png"
class="" title="action.png"
>
<h2 id="其他">其他</h2>
<h3 id="gitalk-评论支持">gitalk 评论支持</h3>
<p><a class="link" href="https://redefine-docs.evanluo.top/docs/configuration-guide/comment#gitalk" >https://redefine-docs.evanluo.top/docs/configuration-guide/comment#gitalk<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<p>[redefine <= v0.4.5 gitalk 代码有<a class="link" href="https://github.com/EvanNotFound/hexo-theme-redefine/issues/36" >bug #36<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>]</p>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">comment:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">use:</span> <span class="string">gitalk</span> <span class="comment"># values: waline | gitalk | twikoo</span></span><br><span class="line"> <span class="comment"># Gitalk</span></span><br><span class="line"> <span class="comment"># See: https://github.com/gitalk/gitalk</span></span><br><span class="line"> <span class="attr">gitalk:</span></span><br><span class="line"> <span class="attr">github_id:</span> <span class="string">attson</span> <span class="comment"># GitHub repo owner</span></span><br><span class="line"> <span class="attr">repository:</span> <span class="string">attson.github.io</span> <span class="comment"># Repository name to store issues</span></span><br><span class="line"> <span class="attr">client_id:</span> <span class="string"><GitHub</span> <span class="string">Application</span> <span class="string">Client</span> <span class="string">ID></span> <span class="comment"># GitHub Application Client ID</span></span><br><span class="line"> <span class="attr">client_secret:</span> <span class="string"><GitHub</span> <span class="string">Application</span> <span class="string">Client</span> <span class="string">Secret></span> <span class="comment"># GitHub Application Client Secret</span></span><br></pre></td></tr></table></figure></div>
<h4 id="新建github-oath-应用">新建github oath 应用</h4>
<p><a class="link" href="https://github.com/settings/applications/new" >https://github.com/settings/applications/new<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/build-blog/application.png"
class="" title="comment.png"
>
<h3 id="markdown-嵌套图片的问题">markdown 嵌套图片的问题</h3>
<ul>
<li>官方推荐的嵌入图片的方式 <a class="link" href="https://hexo.io/zh-tw/docs/tag-plugins#Embed-image" >https://hexo.io/zh-tw/docs/tag-plugins#Embed-image<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 不太符合markdown 通用写法</li>
</ul>
<p>本站点使用 <a class="link" href="https://github.com/yiyungent/hexo-asset-img" >https://github.com/yiyungent/hexo-asset-img<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 插件</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">npm install hexo-asset-img --save</span><br></pre></td></tr></table></figure></div>
<h3 id="markdown-默认渲染器">markdown 默认渲染器</h3>
<ul>
<li>
<p>hexo 默认使用 hexo-renderer-marked 对 markdown 渲染,渲染库支持的语法和功能较少,无法用插件方式新增其他语法,</p>
</li>
<li>
<p>推荐使用 <a class="link" href="https://github.com/hexojs/hexo-renderer-markdown-it" >hexo-renderer-markdown-it<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>, 默认支持的语法更多,也可以添加额外的插件</p>
</li>
</ul>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">npm uninstall hexo-renderer-marked --save</span><br><span class="line"></span><br><span class="line">npm install hexo-renderer-markdown-it --save</span><br></pre></td></tr></table></figure></div>
<h3 id="参考">参考</h3>
<ul>
<li>seo 优化 <a class="link" href="https://juejin.cn/post/6844904178452529160" >https://juejin.cn/post/6844904178452529160<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ul>
]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>example</tag>
</tags>
</entry>
<entry>
<title>centos 安装 shadowsocks</title>
<url>/p/centos-shadowsocks.html</url>
<content><![CDATA[<h2 id="使用版本">使用版本</h2>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">CentOS Linux release 7.6.1810 (Core)</span><br><span class="line">Linux ecs-w0xX6 3.10.0-957.12.2.el7.x86_64 #1 SMP Tue May 14 21:24:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux</span><br><span class="line">Shadowsocks Libev 3.3.5</span><br></pre></td></tr></table></figure></div>
<h2 id="一、手动编译安装">一、手动编译安装</h2>
<p>参考:<br>
- <a class="link" href="https://github.com/shadowsocks/shadowsocks-libev#fedora%E2%80%94rhel" >https://github.com/shadowsocks/shadowsocks-libev#fedora—rhel<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br>
- <a class="link" href="https://b.awei.pub/2019/03/shadowsocks-libev/" >https://b.awei.pub/2019/03/shadowsocks-libev/<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<h3 id="1-安装">1. 安装</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">yum install epel-release -y</span><br><span class="line"></span><br><span class="line">yum install git gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y</span><br><span class="line"></span><br><span class="line">git clone https://github.com/shadowsocks/shadowsocks-libev.git</span><br><span class="line"></span><br><span class="line">cd shadowsocks-libev</span><br><span class="line">git submodule update --init --recursive</span><br><span class="line"></span><br><span class="line">sh autogen.sh</span><br><span class="line"></span><br><span class="line">./configure --disable-documentation</span><br><span class="line"></span><br><span class="line">make && make install</span><br></pre></td></tr></table></figure></div>
<h3 id="2-配置systemctl-管理">2. 配置systemctl 管理</h3>
<h5 id="添加服务配置">+ 添加服务配置</h5>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">cp shadowsocks-libev/rpm/SOURCES/systemd/shadowsocks-libev.service /usr/lib/systemd/system/</span><br><span class="line">cp shadowsocks-libev/rpm/SOURCES/systemd/shadowsocks-libev.default /etc/sysconfig/shadowsocks-libev</span><br></pre></td></tr></table></figure></div>
<p>注意检查 shadowsocks-libev/rpm/SOURCES/systemd/shadowsocks-libev.service 文件</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">ExecStart=/usr/bin/ss-server -c "$CONFFILE" $DAEMON_ARGS</span><br></pre></td></tr></table></figure></div>
<p>/usr/bin/ss-server 改成 ss-server 的安装目录 默认是在 /usr/local/bin/ss-server</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">ExecStart=/usr/local/bin/ss-server -c "$CONFFILE" $DAEMON_ARGS</span><br></pre></td></tr></table></figure></div>
<h5 id="操作命令">+ 操作命令</h5>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">systemctl enable shadowsocks-libev</span><br><span class="line">systemctl start shadowsocks-libev</span><br><span class="line">systemctl stop shadowsocks-libev</span><br><span class="line">systemctl status shadowsocks-libev</span><br></pre></td></tr></table></figure></div>
<h2 id="相关问题和方案">相关问题和方案</h2>
<h3 id="1-This-system-doesn’t-provide-enough-entropy-to-quickly-generate-high-quality-random-numbers">1. This system doesn’t provide enough entropy to quickly generate high-quality random numbers.</h3>
<p><a class="link" href="https://github.com/shadowsocks/shadowsocks-libev/issues/1384" >参考<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">2020-10-23 22:27:03 INFO: binding to outbound IPv4 addr: 127.0.0.1</span><br><span class="line">2020-10-23 22:27:03 INFO: using tcp fast open</span><br><span class="line">2020-10-23 22:27:03 INFO: UDP relay enabled</span><br><span class="line">2020-10-23 22:27:03 INFO: initializing ciphers... chacha20</span><br><span class="line">2020-10-23 22:27:03 INFO: This system doesn't provide enough entropy to quickly generate high-quality random numbers.</span><br><span class="line">Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.</span><br><span class="line">On virtualized Linux environments, also consider using virtio-rng.</span><br><span class="line">The service will not start until enough entropy has been collected.</span><br></pre></td></tr></table></figure></div>
<p>解决方案:</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">yum install -y rng-tools</span><br><span class="line">rngd -r /dev/urandom</span><br></pre></td></tr></table></figure></div>
<h3 id="2-tcp-fast-open-未开启">2. tcp fast open 未开启</h3>
<p>如果未开启<a class="link" href="https://blog.csdn.net/Windgs_YF/article/details/94743088" >tcp fast open<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>会出现如下报错</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">2020-10-23 22:27:04 ERROR: fast open is not supported on this platform</span><br></pre></td></tr></table></figure></div>
<img
lazyload
src="/images/loading.svg"
data-src="/p/centos-shadowsocks/fast_open.jpg"
class="" title="tcp fast open"
>
<p>解决方案:</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">echo 1 > /proc/sys/net/ipv4/tcp_fastopen</span><br></pre></td></tr></table></figure></div>
<h3 id="3-ss-sever-升级到3-2-0-时-fast-open-connect-Invalid-argument">3. ss-sever 升级到3.2.0+ 时 fast_open_connect: Invalid argument</h3>
<p><a class="link" href="https://github.com/shadowsocks/shadowsocks-libev/issues/2196" >参考<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">2020-10-23 23:29:15 ERROR: fast_open_connect: Invalid argument</span><br><span class="line">2020-10-23 23:29:15 ERROR: getpeername: Transport endpoint is not connected</span><br></pre></td></tr></table></figure></div>
<p>解决方案:</p>
<p>删除配置中的 local_address local_port</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/centos-shadowsocks/getpeername.jpg"
class="" title="getpeername"
>
<h2 id="其他">其他</h2>
<h4 id="centos7-记得配置防火墙">centos7 记得配置防火墙</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">firewall-cmd --permanent --add-port={PORT/tcp,PORT/udp}</span><br><span class="line">firewall-cmd --reload</span><br><span class="line">firewall-cmd --list-all</span><br></pre></td></tr></table></figure></div>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>linux</tag>
<tag>shadowsocks</tag>
<tag>centos</tag>
</tags>
</entry>
<entry>
<title>基于 Cloudflare 加速(中转)节点访问</title>
<url>/p/cloudflare_cdn_proxy.html</url>
<content><![CDATA[<p>前提:</p>
<ol>
<li>你需要具备外币卡/Paypal (只开通服务,不收费)</li>
<li>两个主域名</li>
</ol>
<h2 id="CDN-技术">CDN 技术</h2>
<p>在配置之前,在简单说一下cdn技术</p>
<p>内容交付网络(CDN) 是一组分布在不同地理位置的服务器,它将Web 内容存放在更靠近用户的位置,从而加速Web 内容的交付</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img2.png"
class="" title="img.png"
>
<p>简而言之</p>
<ol>
<li>cdn 就是一个服务商搭建的一套网状覆盖区域的 节点池</li>
<li>每个节点都会缓存静态资源</li>
<li>cdn访问就近的节点,如果该节点无所需资源,会按照cdn服务商自己的链路往上游节点访问,直至访问到 <strong>源站</strong></li>
</ol>
<p>结论,当你的所有资源都是非静态资源(或者缓存策略都是不缓存),那就会按照 cdn 服务商优化链路,访问到源站,即 <strong>DCDN</strong></p>
<p><strong>当然有一些服务商提供的CDN只支持静态资源,就无法作为流量节点加速使用</strong></p>
<h2 id="简易流程">简易流程</h2>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">客户端 -> [cloudflare ip/域名 -> 回源策略] -> server.ip</span><br></pre></td></tr></table></figure></div>
<h2 id="先讲原理">先讲原理</h2>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">127.0.0.1 -> 104.27.112.31 (cf 公共cnd节点 ip) -> server.ip</span><br></pre></td></tr></table></figure></div>
<h4 id="为什么通过-cf-ip-能够直接访问到-server-ip"><strong>为什么通过 cf ip 能够直接访问到 server.ip?</strong></h4>
<p>难道是 cf 里面可以直接配置 ip -> server.ip 的反向代理?类似 nginx ?</p>
<p>显然不是那么简单,如果是单纯使用nginx ip 代理方案,那不就是所有人访问这个公共ip 都会指向自己的server.ip 了。</p>
<p>所以上面的链路体现的不完善,再完善上面的链路:</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">127.0.0.1 -> my.server.com + 104.27.112.31 (cf 公共cnd节点 ip) -> server.ip</span><br></pre></td></tr></table></figure></div>
<p>在真实的链路中,需要指定自己的域名,然后cf根据 “域名->server.ip 的映射关系”,完成代理链路</p>
<p>理论成立开始实操</p>
<h2 id="Cloudflare-配置">Cloudflare 配置</h2>
<p>在 Cloudflare 中的 DCDN 产品,是 <strong>网站服务里面 -> SSL/TLS -> 自定义主机名</strong> 提供的</p>
<p>所以在上述的理论链路在cf平台配置后实际链路是这样的</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">127.0.0.1 -> my.server.com + 104.27.112.31 (cf 公共cnd节点 ip) -> ssl/tls 回源策略 -> 回源域名 -> 回源域名dns解析 -> server.ip</span><br></pre></td></tr></table></figure></div>
<ul>
<li><em><strong>回源域名必须是在 cf 管理的域名</strong></em> (回源域名其实在使用时对用户时无感的,只用于回源域名解析)</li>
<li><em><strong><a class="link" href="http://my.server.com" >my.server.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 必须是非 cf 管理的域名</strong></em> (用户真实使用的域名)</li>
</ul>
<p>所以本质是:</p>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">127.0.0.1 -> 需要加速的节点 </span><br><span class="line">变成</span><br><span class="line">127.0.0.1 -> cf -> 需要加速的节点</span><br></pre></td></tr></table></figure></div>
<p>这个过程需要两个主域名参与配置</p>
<h3 id="配置网站(让CF托管一个域名,用于回源)">配置网站(让CF托管一个域名,用于回源)</h3>
<p>打开:<a class="link" href="https://dash.cloudflare.com/sign-up" >https://dash.cloudflare.com/sign-up<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<p><strong>1、</strong> 注册一个 Cloudflare 账号,有账号的话你就登录啊</p>
<p><strong>2、</strong> 添加主域名,用于回源的</p>
<p>这个域名不重要,用户不会直接访问,如果没有的话,可以找个免费域名平台申请一个</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img3.png"
class="" title="img.png"
>
<p><strong>3、</strong> 选择免费计划,点击继续</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img4.png"
class="" title="img.png"
>
<p><strong>4、</strong> 添加一个dns记录,<strong>用于回源</strong></p>
<p>Cloudflare会自动检测你现在有的DNS记录,自动添加。</p>
<p>如果已经有一条用于回源的记录,A记录或者CNAME都行,则无需再建 (指向服务节点)</p>
<p>如 <a class="link" href="http://origin.test.com" >origin.test.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img5.png"
class="" title="img.png"
>
<p><strong>5、</strong> 修改该主域名的dns解析,让CF管理</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img6.png"
class="" title="img.png"
>
<p><strong>具体如何修改,不同的运营商方式不同,以阿里云为例</strong></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img7.png"
class="" title="img.png"
>
<p><strong>6、</strong> DNS托管完成后,回到CF平台,开启SaaS服务,<strong>需要绑定外币卡/Paypal</strong>,不会扣费</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img8.png"
class="" title="img_1.png"
>
<p><strong>7、</strong> 配置 SSL/TLS -> 自定义主机名 -> 回退源</p>
<ul>
<li>回退源就是上面配置的 <a class="link" href="http://origin.test.com" >origin.test.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ul>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img9.png"
class="" title="img.png"
>
<p>添加后点击刷新,正常情况下 回退源状态 应为:有效</p>
<p><strong>8、</strong> 添加自定义主机名。该域名就是真实加速域名,必须是非CF管理域名</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img10.png"
class="" title="img.png"
>
<p><strong>9、</strong> 配置主机名和SSL验证,CF需要验证你有该域名的管理权限和下发SSL证书</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img11.png"
class="" title="img.png"
>
<p><strong>回到你的需要加速域名的域名管理平台,添加dns txt记录,用于验证主机。以阿里云为例</strong></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img12.png"
class="" title="img.png"
>
<p><strong>主机名验证完成后,添加dns txt记录,用于颁发SSL。以阿里云为例</strong></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img13.png"
class="" title="img.png"
>
<p><strong>都验证完成后状态</strong></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img14.png"
class="" title="img.png"
>
<p><strong>10、</strong> 最后确保 <a class="link" href="http://blog.mysite.com" >blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 解析到CF上,A记录或者CNAME</p>
<ul>
<li>A记录解析到CF ip上 (优选ip)</li>
<li>CNAME解析到CF 域名上 (优选域名)</li>
</ul>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img15.png"
class="" title="img.png"
>
<p><strong>此时,访问 <a class="link" href="http://blog.mysite.com" >blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 就会通过CF节点,并回源到 <a class="link" href="http://origin.test.com" >origin.test.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></strong></p>
<h2 id="注意事项">注意事项</h2>
<p>默认情况下,选择回源的模式是 灵活,意味着 CF -> <a class="link" href="http://origin.test.com" >origin.test.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 走的都是80端口,无SSL</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img16.png"
class="" title="img.png"
>
<p>比如 curl <a class="link" href="http://blog.mysite.com" >http://blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> or curl <a class="link" href="https://blog.mysite.com" >https://blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<p>都是相当于 curl <a class="link" href="http://origin.test.com" >http://origin.test.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<hr>
<p>但是实测当 curl <a class="link" href="https://blog.mysite.com:8443" >https://blog.mysite.com:8443<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 时,cf 会强制后端链路需要SSL, 相当于 curl <a class="link" href="http://origin.test.com:8443" >http://origin.test.com:8443<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<p><a class="link" href="https://developers.cloudflare.com/fundamentals/reference/network-ports/" >其他支持的端口没有测试<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<h3 id="如何调整回源端口和SSL策略">如何调整回源端口和SSL策略</h3>
<p><strong>1、</strong> SSL 策略</p>
<p>方式一、在上图中调整为 <strong>完全模式</strong>,则会按照请求端口并使用SSL建立回源链接。(这个配置会对该域下所有的自定义主机名生效)</p>
<p>方式二、通过规则配置,针对不同规则应用配置,比如指定 <a class="link" href="http://blog.mysite.com" >blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 的回源是使用 <strong>完全模式</strong></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img17.png"
class="" title="img.png"
>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img18.png"
class="" title="img.png"
>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img19.png"
class="" title="img.png"
>
<p><strong>2、</strong> 回源端口自定义</p>
<p>比如想要实现 curl <a class="link" href="http://blog.mysite.com" >http://blog.mysite.com<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> -> curl <a class="link" href="https://origin.test.com:8443" >https://origin.test.com:8443<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img20.png"
class="" title="img.png"
>
<img
lazyload
src="/images/loading.svg"
data-src="/p/cloudflare_cdn_proxy/img21.png"
class="" title="img.png"
>
<h3 id="其他说明">其他说明</h3>
<ul>
<li>因为节点基本在海外,所以套CF中转,速度不会很理想</li>
<li>但是使用移动网络的话,可能会使用 Cloudflare 香港节点,理论上会有不错的速度</li>
<li>作为代理的话,可以用于防止 ip 被墙或者已经被墙</li>
<li>作为免费cdn,会有一定的价值,毕竟不会被墙</li>
<li>这套方案理论上可以做其他更多的事情</li>
<li>如果过程中出现5xx 4xx
<ul>
<li>请检查是否一个主域名在CF管理,一个在其他平台</li>
<li>请检查回源端口和回源ssl策略</li>
</ul>
</li>
</ul>
<h3 id="参考链接">参考链接</h3>
<ul>
<li><a class="link" href="https://github.com/233boy/v2ray/wiki/%E4%BD%BF%E7%94%A8Cloudflare%E4%B8%AD%E8%BD%ACV2Ray%E6%B5%81%E9%87%8F" >https://github.com/233boy/v2ray/wiki/使用Cloudflare中转V2Ray流量<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
<li><a class="link" href="https://linux.do/t/topic/114314" >https://linux.do/t/topic/114314<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ul>
]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>network</tag>
</tags>
</entry>
<entry>
<title>Composer 私有仓库搭建</title>
<url>/p/composer-private.html</url>
<content><![CDATA[<h1>Composer 私有仓库搭建</h1>
<p>composer 私有仓库搭建方案有以下三种</p>
<ol>
<li>
<p><a class="link" href="https://github.com/composer/satis" title="Satis">Satis<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 官方推荐的工具</p>
<p>基本满足要求,缺点就是增加自己的package每次需要手动修改配置,版本更新需要手动,比较繁琐</p>
</li>
<li>
<p><a class="link" href="https://github.com/ludofleury/satisfy" title="Satisfy">Satisfy<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 在Satis基础上增加了一些便捷的功能,webhook,图形界面增加仓库等</p>
</li>
<li>
<p>coding by yourself.;</p>
</li>
</ol>
<p>本文使用 <a class="link" href="https://github.com/ludofleury/satisfy" title="Satisfy">Satisfy<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> + docker进行搭建</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_a4urwWFHJZ.png"
class=""
>
<h2 id="一、下载">一、下载</h2>
<p>选择一个目录 /var/www/satisfy (<em>该目录要与后面容器内的目录保持一致</em>);</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line"># current commit hash master@7e2a472</span><br><span class="line">git clone https://github.com/ludofleury/satisfy /var/www/satisfy</span><br><span class="line"></span><br><span class="line">cd /var/www/satisfy</span><br><span class="line"></span><br><span class="line">chown -R www-data:www-data .</span><br></pre></td></tr></table></figure></div>
<h2 id="二、配置docker">二、配置docker</h2>
<h3 id="Dockerfile">Dockerfile</h3>
<p>修改docker/php/Dockerfile</p>
<p>(因为本文nginx 是宿主机提供的,不是独立一个nginx 容器,配置上与官方有些差异)</p>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line"><span class="keyword">FROM</span> php:<span class="number">8.0</span>-fpm</span><br><span class="line"></span><br><span class="line"><span class="comment"># 国内源加速</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> sed -i s/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt update && \</span></span><br><span class="line"><span class="language-bash"> apt install -qy wget curl git zip unzip && \</span></span><br><span class="line"><span class="language-bash"> apt clean && <span class="built_in">rm</span> -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 保证外部的www-data 与 容器内的 www-data uid、gid 相同</span></span><br><span class="line"><span class="keyword">ARG</span> UNAME=www-data</span><br><span class="line"><span class="keyword">ARG</span> UGROUP=www-data</span><br><span class="line"><span class="keyword">ARG</span> UID=<span class="number">1000</span></span><br><span class="line"><span class="keyword">ARG</span> GID=<span class="number">1000</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> usermod --uid <span class="variable">$UID</span> <span class="variable">$UNAME</span></span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> groupmod --gid <span class="variable">$GID</span> <span class="variable">$UGROUP</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> wget -O /usr/local/bin/composer https://getcomposer.org/download/latest-stable/composer.phar && <span class="built_in">chmod</span> +x /usr/local/bin/composer</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># gitlab ssh</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> id_rsa /var/www/.ssh/id_rsa</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">chmod</span> 0600 /var/www/.ssh/id_rsa</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> php.ini /usr/local/etc/php/conf.d/satisfy.ini</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">mkdir</span> -p /var/www/.ssh && <span class="built_in">chmod</span> 0700 /var/www/.ssh && ssh-keyscan -H github.com >> /var/www/.ssh/known_hosts && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">mkdir</span> -p /var/www/.composer && <span class="built_in">chown</span> www-data:www-data /var/www/.composer</span></span><br><span class="line"> </span><br><span class="line"><span class="comment"># 保证 www-data 用户权限</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">chown</span> -R www-data:www-data /var/www</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># gitlab ssh known_hosts, 不优先添加,webhook 处理在ssh方式下会处理异常</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> ssh-keyscan -p 222 -H <my.gitlab.com> >> /var/www/.ssh/known_hosts</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">USER</span> www-data</span><br></pre></td></tr></table></figure></div>
<h3 id="DockerCompose">DockerCompose</h3>
<p>修改 docker-composer.yml</p>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">version: <span class="string">'3'</span></span><br><span class="line">services:</span><br><span class="line"> php:</span><br><span class="line"> build:</span><br><span class="line"> context: ./docker/php</span><br><span class="line"> container_name: satisfy_php</span><br><span class="line"> <span class="keyword">user</span>: www-data</span><br><span class="line"> working_dir: /var/www/satisfy</span><br><span class="line"> volumes:</span><br><span class="line"> - .:/var/www/satisfy</span><br><span class="line"> - /var/www/.composer</span><br><span class="line"> environment:</span><br><span class="line"> APP_ENV: ${APP_ENV:-dev}</span><br><span class="line"> APP_DEBUG: ${APP_DEBUG:-<span class="number">1</span>}</span><br><span class="line"> APP_PATH: /var/www/satisfy</span><br><span class="line"> ports:</span><br><span class="line"> - <span class="number">9000</span>:<span class="number">9000</span></span><br></pre></td></tr></table></figure></div>
<h3 id="Build">Build</h3>
<ol>
<li>在 docker/php/ 目录下增加 gitlab 的 ssh id_rsa</li>
<li>docker-composer build</li>
</ol>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line"> $ docker-composer build</span><br><span class="line"> ...</span><br><span class="line"> ---> <span class="number">8346930</span>c5d07</span><br><span class="line">Removing intermediate container e1af8c887943</span><br><span class="line">Step <span class="number">17</span>/<span class="number">17</span> : <span class="keyword">USER</span> www-data</span><br><span class="line"> ---> Running in d77d9a8ca62b</span><br><span class="line"> ---> <span class="number">8</span>bba196f3d47</span><br><span class="line">Removing intermediate container d77d9a8ca62b</span><br><span class="line">Successfully built <span class="number">8</span>bba196f3d47</span><br></pre></td></tr></table></figure></div>
<h2 id="三、配置satisfy">三、配置satisfy</h2>
<h3 id="vendor依赖下载">vendor依赖下载</h3>
<p>直接使用该镜像中的composer 进行依赖下载</p>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">docker <span class="keyword">run</span><span class="language-bash"> --<span class="built_in">rm</span> -it -v <span class="variable">$PWD</span>:/var/www/app satisfy_php composer install -d /var/www/app</span></span><br></pre></td></tr></table></figure></div>
<p>提示输入配置选项可以直接回车跳过,后续手动修改</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_d406ohIHKM.png"
class=""
>
<h3 id="satis-初始化">satis 初始化</h3>
<h4 id="增加配置文件-satis-json">增加配置文件 satis.json</h4>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="string">"name"</span>: <span class="string">"attson/repository"</span>,</span><br><span class="line"> <span class="string">"homepage"</span>: <span class="string">"http://composer.attson.com/"</span>,</span><br><span class="line"> <span class="string">"repositories"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="string">"type"</span>: <span class="string">"vcs"</span>,</span><br><span class="line"> <span class="string">"url"</span>: <span class="string">"ssh://git@<gitlab.com/group/project>.git"</span></span><br><span class="line"> }</span><br><span class="line"> ],</span><br><span class="line"> <span class="string">"require-all"</span>: true,</span><br><span class="line"> <span class="string">"config"</span>: {</span><br><span class="line"> <span class="string">"secure-http"</span>: false</span><br><span class="line"> },</span><br><span class="line"> <span class="string">"archive"</span>: {</span><br><span class="line"> <span class="string">"directory"</span>: <span class="string">"dist"</span>,</span><br><span class="line"> <span class="string">"format"</span>: <span class="string">"zip"</span>,</span><br><span class="line"> <span class="string">"skip-dev"</span>: false,</span><br><span class="line"> <span class="string">"prefix-url"</span>: <span class="string">"http://composer.attson.com/"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div>
<h4 id="build-satis">build satis</h4>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">docker <span class="keyword">run</span><span class="language-bash"> --<span class="built_in">rm</span> -it -v <span class="variable">$PWD</span>:/var/www/app satisfy_php php /var/www/app/bin/satis build /var/www/app/satis.json /var/www/app/public -vvv</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">Writing packages.json</span><br><span class="line">Pruning include directories</span><br><span class="line">Writing web view</span><br></pre></td></tr></table></figure></div>
<h3 id="satisfy配置">satisfy配置</h3>
<h4 id="修改-config-parameters-yml">修改 config/parameters.yml</h4>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">parameters:</span><br><span class="line"> secret: <any strings></span><br><span class="line"> satis_filename: <span class="string">'%kernel.project_dir%/satis.json'</span></span><br><span class="line"> satis_log_path: <span class="string">'%kernel.project_dir%/var/satis'</span></span><br><span class="line"> gitlab.secret: <webhook.token></span><br><span class="line"> admin.auth: true</span><br><span class="line"> admin.users:</span><br><span class="line"> admin:</span><br><span class="line"> password: <plaintext></span><br><span class="line"> roles:</span><br><span class="line"> - ROLE_ADMIN</span><br><span class="line"> composer.home: <span class="string">'%kernel.project_dir%/var/composer'</span></span><br></pre></td></tr></table></figure></div>
<p><a class="link" href="https://github.com/ludofleury/satisfy/blob/master/config/security.yml" >https://github.com/ludofleury/satisfy/blob/master/config/security.yml<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br>
默认密码使用的是明文方式</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_Y7nrAZFoCu.png"
class=""
>
<h4 id="启动服务">启动服务</h4>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">docker-composer up -d</span><br></pre></td></tr></table></figure></div>
<h3 id="nginx-配置">nginx 配置</h3>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">server {</span><br><span class="line"> listen <span class="number">80</span>;</span><br><span class="line"> server_name composer.attson.com;</span><br><span class="line"></span><br><span class="line"> access_log /var/log/nginx/composer/access.log;</span><br><span class="line"> error_log /var/log/nginx/composer/error_log;</span><br><span class="line"></span><br><span class="line"> root /var/www/satisfy/public;</span><br><span class="line"> index index.html index.php;</span><br><span class="line"> location / {</span><br><span class="line"> try_files $uri $uri/ /index.php?$query_string;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> location ~ ^(.+\.php)(.*) {</span><br><span class="line"> try_files $uri /index.php =<span class="number">404</span>;</span><br><span class="line"></span><br><span class="line"> fastcgi_split_path_info ^(.+\.php)(.*)$;</span><br><span class="line"> fastcgi_pass <span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">9000</span>;</span><br><span class="line"></span><br><span class="line"> fastcgi_param PATH_INFO $fastcgi_path_info;</span><br><span class="line"> <span class="comment"># fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;</span></span><br><span class="line"> fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;</span><br><span class="line"> include fastcgi_params;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div>
<h2 id="四、验证">四、验证</h2>
<h3 id="访问地址">访问地址</h3>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_AuHbRj7-fo.png"
class=""
>
<h3 id="访问-admin-configuration">访问 admin/configuration</h3>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_vo4axt7ZmP.png"
class=""
>
<p>用户名密码 在 parameters.yml 配置文件</p>
<h3 id="gitlab-webhook">gitlab webhook;</h3>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_K0Pz3doYO3.png"
class=""
>
<p>webhook 配置完后可以test</p>
<img
lazyload
src="/images/loading.svg"
data-src="/p/composer-private/image_uncVKUkl8y.png"
class=""
>
<p>不出意外的话,就全部搭好了</p>
<h2 id="五、重新拉取">五、重新拉取</h2>
<p>可以通过删除所有文件,清理无效的版本。(如果仓库太多的话,还是不要这么操作,全部拉取比较耗时)</p>
<div class="code-container" data-rel="Docker"><figure class="iseeu highlight docker"><table><tr><td class="code"><pre><span class="line">rm -rf public/dist</span><br><span class="line"></span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> --<span class="built_in">rm</span> -it -v <span class="variable">$PWD</span>:/var/www/app satisfy_php php /var/www/app/bin/satis build /var/www/app/satis.json /var/www/app/public -vvv</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 注意 public 的文件权限</span></span><br><span class="line">chown -R www-data:www-data public</span><br></pre></td></tr></table></figure></div>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>example</tag>
<tag>php</tag>
</tags>
</entry>
<entry>
<title>Hexo Gitalk 评论自动初始化</title>
<url>/p/gitalk-init.html</url>
<content><![CDATA[<h1>Hexo Gitalk 评论自动初始化</h1>
<h2 id="背景">背景</h2>
<p>如果使用 Gitalk 评论插件,需要作者为每篇文章手动操作一下初始化,生成对应文章的issue,才能进行评论。</p>
<p>偷懒的程序员当然不喜欢这么繁琐的流程,所以需要一个自动化工具</p>
<h2 id="自动化实现流程">自动化实现流程</h2>
<img
lazyload
src="/images/loading.svg"
data-src="/p/gitalk-init/workflows.png"
class="" title="img.png"
>
<h2 id="执行效果">执行效果</h2>
<img
lazyload
src="/images/loading.svg"
data-src="/p/gitalk-init/result.png"
class="" title="img.png"
>
<h2 id="具体代码">具体代码</h2>
<p><a class="link" href="https://github.com/attson/hexo-gitalk-init" >https://github.com/attson/hexo-gitalk-init<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
<ul>
<li>无需安装其他的依赖,让你的hexo项目更干净</li>
<li>不需要依赖或修改sitemap</li>
<li>更适合自动化</li>
<li>代码强迫症福音 no any warning</li>
</ul>
<div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">const</span> readline = <span class="built_in">require</span>(<span class="string">'readline'</span>);</span><br><span class="line"><span class="keyword">const</span> https = <span class="built_in">require</span>(<span class="string">'https'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> config = {}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">'gitalk_init.json'</span>))) {</span><br><span class="line"> config = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(fs.<span class="title function_">readFileSync</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">'gitalk_init.json'</span>)).<span class="title function_">toString</span>(<span class="string">'utf-8'</span>))</span><br><span class="line"></span><br><span class="line"> <span class="title class_">Object</span>.<span class="title function_">keys</span>(config).<span class="title function_">forEach</span>(<span class="function"><span class="params">key</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> value = config[key];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> reg = <span class="regexp">/{process\.env\.[a-zA-Z_\-}]*/gm</span></span><br><span class="line"></span><br><span class="line"> value.<span class="title function_">match</span>(reg).<span class="title function_">forEach</span>(<span class="function"><span class="params">match</span> =></span> {</span><br><span class="line"> config[key].<span class="title function_">replace</span>(match, process.<span class="property">env</span>[match.<span class="title function_">substring</span>(<span class="number">13</span>, match.<span class="property">length</span> - <span class="number">1</span>)])</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 配置信息</span></span><br><span class="line"> config = {</span><br><span class="line"> <span class="comment">// GitHub repository 所有者,可以是个人或者组织。对应Gitalk配置中的owner</span></span><br><span class="line"> <span class="attr">username</span>: process.<span class="property">env</span>.<span class="property">GITHUB_REPOSITORY_OWNER</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 储存评论issue的github仓库名,仅需要仓库名字即可。对应 Gitalk配置中的repo</span></span><br><span class="line"> <span class="attr">repo</span>: process.<span class="property">env</span>.<span class="property">GITALK_INIT_REPO</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从 GitHub 的 Personal access tokens 页面,点击 Generate new token</span></span><br><span class="line"> <span class="attr">token</span>: process.<span class="property">env</span>.<span class="property">GITALK_TOKEN</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 是否启用缓存,启用缓存会将已经初始化的数据写入配置的 outputCacheFile 文件,下一次直接通过缓存文件 outputCacheFile 判断</span></span><br><span class="line"> <span class="attr">enableCache</span>: process.<span class="property">env</span>.<span class="property">GITALK_INIT_CACHE</span> || <span class="literal">true</span>,</span><br><span class="line"> <span class="comment">// 缓存文件输出的位置</span></span><br><span class="line"> <span class="attr">cacheFile</span>: process.<span class="property">env</span>.<span class="property">GITALK_INIT_CACHE_FILE</span> || path.<span class="title function_">join</span>(__dirname, <span class="string">'./public/gitalk-init-cache.json'</span>),</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 只用于获取缓存的来源,缓存仍然会写到 cacheFile. 读取优先级 cacheFile > cacheRemote. 故cacheFile文件存在时,忽略 cacheRemote</span></span><br><span class="line"> <span class="attr">cacheRemote</span>: process.<span class="property">env</span>.<span class="property">GITALK_INIT_CACHE_REMOTE</span>,</span><br><span class="line"> <span class="comment">// 通过远程读取文件,这样就不需要在本地的博客源文件中保存(保存在静态站点的public中)</span></span><br><span class="line"> <span class="comment">// output 到 public 目的就是将文件放在静态站点里面,下一次构建时,可以从远程读取</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">postsDir</span>: process.<span class="property">env</span>.<span class="property">GITALK_INIT_POSTS_DIR</span> || <span class="string">'source/_posts'</span></span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">configInit</span>(<span class="params">config</span>) {</span><br><span class="line"> <span class="keyword">if</span> (config.<span class="property">repo</span> === <span class="literal">undefined</span>) {</span><br><span class="line"> config.<span class="property">repo</span> = <span class="string">`<span class="subst">${config.username}</span>.github.io`</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (config.<span class="property">cacheRemote</span> === <span class="literal">undefined</span>) {</span><br><span class="line"> config.<span class="property">cacheRemote</span> = <span class="string">`https://<span class="subst">${config.repo}</span>/gitalk-init-cache.json`</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title function_">configInit</span>(config)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> hostname = <span class="string">'api.github.com'</span></span><br><span class="line"><span class="keyword">const</span> apiPath = <span class="string">'/repos/'</span> + config.<span class="property">username</span> + <span class="string">'/'</span> + config.<span class="property">repo</span> + <span class="string">'/issues'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> autoGitalkInit = {</span><br><span class="line"> <span class="attr">gitalkCache</span>: <span class="literal">null</span>,</span><br><span class="line"> <span class="attr">gitalkIdGenerator</span>: <span class="literal">null</span>,</span><br><span class="line"> getFiles (dir, files_) {</span><br><span class="line"> files_ = files_ || [];</span><br><span class="line"> <span class="keyword">const</span> files = fs.<span class="title function_">readdirSync</span>(dir);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">in</span> files) {</span><br><span class="line"> <span class="keyword">let</span> name = dir + <span class="string">'/'</span> + files[i];</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">statSync</span>(name).<span class="title function_">isDirectory</span>()) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">getFiles</span>(name, files_);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (name.<span class="title function_">endsWith</span>(<span class="string">'.md'</span>)) {</span><br><span class="line"> files_.<span class="title function_">push</span>(name);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> files_;</span><br><span class="line"> },</span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">readItem</span>(<span class="params">file</span>) {</span><br><span class="line"> <span class="keyword">const</span> fileStream = fs.<span class="title function_">createReadStream</span>(file);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> rl = readline.<span class="title function_">createInterface</span>({</span><br><span class="line"> <span class="attr">input</span>: fileStream,</span><br><span class="line"> <span class="attr">crlfDelay</span>: <span class="title class_">Infinity</span>,</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">// Note: we use the crlfDelay option to recognize all instances of CR LF</span></span><br><span class="line"> <span class="comment">// ('\r\n') in input.txt as a single line break.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> start = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> post = {};</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">await</span> (<span class="keyword">const</span> line <span class="keyword">of</span> rl) {</span><br><span class="line"> <span class="keyword">if</span> (start === <span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">if</span> (line.<span class="title function_">trim</span>() === <span class="string">'---'</span>) {</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">const</span> items = line.<span class="title function_">split</span>(<span class="string">':'</span>)</span><br><span class="line"> <span class="keyword">if</span> ([<span class="string">'title'</span>, <span class="string">'desc'</span>, <span class="string">'date'</span>, <span class="string">'comment'</span>].<span class="title function_">indexOf</span>(items[<span class="number">0</span>].<span class="title function_">trim</span>()) !== -<span class="number">1</span>) {</span><br><span class="line"> post[items[<span class="number">0</span>].<span class="title function_">trim</span>()] = items[<span class="number">1</span>].<span class="title function_">trim</span>()</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (line.<span class="title function_">trim</span>() === <span class="string">'---'</span>) {</span><br><span class="line"> start = <span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> fileStream.<span class="title function_">close</span>()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="title function_">keys</span>(post).<span class="property">length</span> === <span class="number">0</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`gitalk: warn read empty from: <span class="subst">${file}</span>`</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (post[<span class="string">'comment'</span>] === <span class="literal">false</span> || post[<span class="string">'comment'</span>] === <span class="string">'false'</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`gitalk: ignore by comment = <span class="subst">${post[<span class="string">'comment'</span>]}</span> : <span class="subst">${file}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(<span class="string">'title'</span> <span class="keyword">in</span> post)) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`gitalk: ignore because the title miss: <span class="subst">${file}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(<span class="string">'date'</span> <span class="keyword">in</span> post)) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`gitalk: ignore because the date miss: <span class="subst">${file}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> regex = <span class="regexp">/^\d{4}-\d{2}-\d{2} \d{2}$/gm</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(regex.<span class="title function_">test</span>(post[<span class="string">'date'</span>]))) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`gitalk: ignore because the date <span class="subst">${post[<span class="string">'date'</span>]}</span> invalid: <span class="subst">${file}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// pathname /year/month/day/file_without_extend/</span></span><br><span class="line"> post[<span class="string">'pathname'</span>] = <span class="string">'/'</span> + post[<span class="string">'date'</span>].<span class="title function_">substring</span>(<span class="number">0</span>, <span class="number">10</span>).<span class="title function_">replace</span>(<span class="regexp">/[-|\s]/g</span>, <span class="string">'/'</span>) + <span class="string">`/<span class="subst">${path.basename(file, <span class="string">'.md'</span>)}</span>/`</span></span><br><span class="line"> post[<span class="string">'desc'</span>] = post[<span class="string">'title'</span>]</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> post</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">readPosts</span>(<span class="params">dir</span>) {</span><br><span class="line"> <span class="keyword">const</span> posts = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> file <span class="keyword">of</span> <span class="variable language_">this</span>.<span class="title function_">getFiles</span>(dir)) {</span><br><span class="line"> <span class="keyword">const</span> post = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">readItem</span>(file);</span><br><span class="line"> <span class="keyword">if</span> (post != <span class="literal">null</span>) {</span><br><span class="line"> posts.<span class="title function_">push</span>(post)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> posts</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用github接口初始化</span></span><br><span class="line"> <span class="title function_">gitalkInitInvoke</span>(<span class="params">{pathname, id, title, desc}</span>) {</span><br><span class="line"> <span class="keyword">const</span> options = {</span><br><span class="line"> <span class="string">'method'</span>: <span class="string">'POST'</span>,</span><br><span class="line"> <span class="string">'hostname'</span>: hostname,</span><br><span class="line"> <span class="string">'path'</span>: apiPath,</span><br><span class="line"> <span class="string">'headers'</span>: {</span><br><span class="line"> <span class="string">'Authorization'</span>: <span class="string">'token '</span> + config.<span class="property">token</span>,</span><br><span class="line"> <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line"> <span class="string">'User-Agent'</span>: config.<span class="property">username</span> + <span class="string">'/'</span> + config.<span class="property">repo</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="string">'maxRedirects'</span>: <span class="number">20</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> link = <span class="string">`https://<span class="subst">${config.repo}</span><span class="subst">${pathname}</span>`</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//创建issue</span></span><br><span class="line"> <span class="keyword">const</span> reqBody = {</span><br><span class="line"> <span class="string">'title'</span>: title,</span><br><span class="line"> <span class="string">'labels'</span>: [<span class="string">'Gitalk'</span>, id],</span><br><span class="line"> <span class="string">'body'</span>: <span class="string">`[<span class="subst">${link}</span>](<span class="subst">${link}</span>})\r\n\r\n<span class="subst">${desc}</span>`</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="keyword">let</span> req = https.<span class="title function_">request</span>(options, <span class="keyword">function</span> (<span class="params">res</span>) {</span><br><span class="line"> <span class="keyword">const</span> chunks = [];</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'data'</span>, <span class="keyword">function</span> (<span class="params">chunk</span>) {</span><br><span class="line"> chunks.<span class="title function_">push</span>(chunk);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'end'</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Buffer</span>.<span class="title function_">concat</span>(chunks).<span class="title function_">toString</span>())</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>([<span class="literal">false</span>, <span class="literal">true</span>]);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> (<span class="params">error</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>([error, <span class="literal">false</span>]);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> req.<span class="title function_">write</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(reqBody))</span><br><span class="line"></span><br><span class="line"> req.<span class="title function_">end</span>();</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 通过github api 请求判断是否已经初始化</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">string</span>} id gitalk 初始化的id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> {<span class="type">Promise<[boolean, boolean]></span>} 第一个值表示是否出错,第二个值 false 表示没初始化, true 表示已经初始化</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> getIsInitByGitHub (id) {</span><br><span class="line"> <span class="keyword">const</span> options = {</span><br><span class="line"> <span class="string">'method'</span>: <span class="string">'GET'</span>,</span><br><span class="line"> <span class="string">'hostname'</span>: hostname,</span><br><span class="line"> <span class="string">'path'</span>: apiPath + <span class="string">'?labels=Gitalk,'</span> + id,</span><br><span class="line"> <span class="string">'headers'</span>: {</span><br><span class="line"> <span class="string">'Authorization'</span>: <span class="string">'token '</span> + config.<span class="property">token</span>,</span><br><span class="line"> <span class="string">'Accept'</span>: <span class="string">'application/json'</span>,</span><br><span class="line"> <span class="comment">// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required</span></span><br><span class="line"> <span class="string">'User-Agent'</span>: config.<span class="property">username</span> + <span class="string">'/'</span> + config.<span class="property">repo</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="string">'maxRedirects'</span>: <span class="number">20</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> req = https.<span class="title function_">request</span>(options, <span class="keyword">function</span> (<span class="params">res</span>) {</span><br><span class="line"> <span class="keyword">const</span> chunks = [];</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'data'</span>, <span class="keyword">function</span> (<span class="params">chunk</span>) {</span><br><span class="line"> chunks.<span class="title function_">push</span>(chunk);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'end'</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> res = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">Buffer</span>.<span class="title function_">concat</span>(chunks).<span class="title function_">toString</span>());</span><br><span class="line"> <span class="keyword">if</span> (res.<span class="property">length</span> > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>([<span class="literal">false</span>, <span class="literal">true</span>]);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>([<span class="literal">false</span>, <span class="literal">false</span>]);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> (<span class="params">error</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>([error, <span class="literal">false</span>]);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> req.<span class="title function_">end</span>();</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 根据缓存,判断链接是否已经初始化</span></span><br><span class="line"> <span class="comment">// 第一个值表示是否出错,第二个值 false 表示没初始化, true 表示已经初始化</span></span><br><span class="line"> <span class="keyword">async</span> idIsInit (id) {</span><br><span class="line"> <span class="keyword">if</span> (!config.<span class="property">enableCache</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">getIsInitByGitHub</span>(id);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 如果通过缓存查询到的数据是未初始化,则再通过请求判断是否已经初始化,防止多次初始化</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> cacheRes = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">getIsInitByCache</span>(id)</span><br><span class="line"> <span class="keyword">if</span> (cacheRes === <span class="literal">false</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(id + <span class="string">' 缓存不存在, 从github获取状态...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">getIsInitByGitHub</span>(id);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> [<span class="literal">false</span>, <span class="literal">true</span>];</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 通过远程地址获取缓存内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> {<span class="type">Promise<Object></span>}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="title function_">getRemoteCache</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> req = https.<span class="title function_">get</span>(config.<span class="property">cacheRemote</span>, <span class="keyword">function</span> (<span class="params">res</span>) {</span><br><span class="line"> <span class="keyword">const</span> chunks = [];</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'data'</span>, <span class="keyword">function</span> (<span class="params">chunk</span>) {</span><br><span class="line"> chunks.<span class="title function_">push</span>(chunk);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'end'</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>(<span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">Buffer</span>.<span class="title function_">concat</span>(chunks).<span class="title function_">toString</span>()));</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.<span class="title function_">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> (<span class="params">error</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">reject</span>(error);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> req.<span class="title function_">end</span>();</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 通过缓存判断是否已经初始化, 优先加载缓存文件,文件不存在则尝试从 cacheRemote 获取</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">string</span>} gitalkId 初始化的id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> {<span class="type">Promise<boolean></span>} false 表示没初始化, true 表示已经初始化</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">getIsInitByCache</span>(<span class="params">gitalkId</span>){</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">gitalkCache</span> === <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">// 判断缓存文件是否存在</span></span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">gitalkCache</span> = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">gitalkCache</span> = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(fs.<span class="title function_">readFileSync</span>(config.<span class="property">cacheFile</span>).<span class="title function_">toString</span>(<span class="string">'utf-8'</span>));</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'读取缓存文件成功 '</span> + config.<span class="property">cacheFile</span>)</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'读取缓存文件失败 '</span> + config.<span class="property">cacheFile</span> + <span class="string">' : '</span> + e.<span class="property">message</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (config.<span class="property">cacheRemote</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'正在从 '</span> + config.<span class="property">cacheRemote</span> + <span class="string">' 读取文件'</span>)</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">gitalkCache</span> = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">getRemoteCache</span>()</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'读取缓存文件成功 '</span> + config.<span class="property">cacheRemote</span>)</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'读取缓存文件失败 '</span> + config.<span class="property">cacheRemote</span> + <span class="string">' : '</span> + e.<span class="property">message</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> that = <span class="variable language_">this</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(<span class="keyword">function</span> (<span class="params">gitalkId</span>) {</span><br><span class="line"> <span class="keyword">if</span> (!that.<span class="property">gitalkCache</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> !!that.<span class="property">gitalkCache</span>.<span class="title function_">find</span>(<span class="function">(<span class="params">{id: itemId}</span>) =></span> (itemId === gitalkId));</span><br><span class="line"> }(gitalkId));</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 写入内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">string</span>} fileName 文件名</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">string</span>} content 内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> <span class="variable">flag</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">fileName, content, flag = <span class="string">'w+'</span></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve</span>) =></span> {</span><br><span class="line"> fs.<span class="title function_">open</span>(fileName, flag, <span class="keyword">function</span> (<span class="params">err, fd</span>) {</span><br><span class="line"> <span class="keyword">if</span> (err) {</span><br><span class="line"> <span class="title function_">resolve</span>([err, <span class="literal">false</span>]);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> fs.<span class="title function_">writeFile</span>(fd, content, <span class="keyword">function</span> (<span class="params">err</span>) {</span><br><span class="line"> <span class="keyword">if</span> (err) {</span><br><span class="line"> <span class="title function_">resolve</span>([err, <span class="literal">false</span>]);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> fs.<span class="title function_">close</span>(fd, <span class="function">(<span class="params">err</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (err) {</span><br><span class="line"> <span class="title function_">resolve</span>([err, <span class="literal">false</span>]);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> <span class="title function_">resolve</span>([<span class="literal">false</span>, <span class="literal">true</span>]);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// 生成 GitalkId</span></span><br><span class="line"> <span class="title function_">getGitalkId</span>(<span class="params">pathname, title, desc, date</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">gitalkIdGenerator</span> == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(<span class="string">"get-gitalk-id.js"</span>)) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">gitalkIdGenerator</span> = <span class="built_in">require</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">"get-gitalk-id.js"</span>)).<span class="property">getGitalkId</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">gitalkIdGenerator</span> = <span class="keyword">function</span> (<span class="params">pathname</span>) {</span><br><span class="line"> <span class="keyword">let</span> id = pathname</span><br><span class="line"></span><br><span class="line"> <span class="comment">// github issue label max 50</span></span><br><span class="line"> <span class="keyword">if</span> (id.<span class="property">length</span> > <span class="number">50</span>) {</span><br><span class="line"> id = id.<span class="title function_">substring</span>(<span class="number">0</span>, <span class="number">50</span> - <span class="number">3</span>) + <span class="string">'...'</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> id</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">gitalkIdGenerator</span>(pathname, title, desc, date)</span><br><span class="line"> },</span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">start</span>(<span class="params">postDir</span>) {</span><br><span class="line"> <span class="keyword">const</span> posts = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">readPosts</span>(postDir);</span><br><span class="line"> <span class="comment">// 报错的数据</span></span><br><span class="line"> <span class="keyword">const</span> errorData = [];</span><br><span class="line"> <span class="comment">// 已经初始化的数据</span></span><br><span class="line"> <span class="keyword">const</span> initializedData = [];</span><br><span class="line"> <span class="comment">// 成功初始化数据</span></span><br><span class="line"> <span class="keyword">const</span> successData = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> item <span class="keyword">of</span> posts) {</span><br><span class="line"> <span class="keyword">const</span> {pathname, title, desc, date} = item;</span><br><span class="line"> <span class="keyword">const</span> id = <span class="variable language_">this</span>.<span class="title function_">getGitalkId</span>(pathname, title, desc, date);</span><br><span class="line"> <span class="keyword">const</span> [err, res] = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">idIsInit</span>(id);</span><br><span class="line"> <span class="keyword">if</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Error: 查询评论异常 [ <span class="subst">${title}</span> ] , 信息:`</span>, err || <span class="string">'无'</span>);</span><br><span class="line"> errorData.<span class="title function_">push</span>({</span><br><span class="line"> ...item,</span><br><span class="line"> <span class="attr">info</span>: <span class="string">'查询评论异常'</span>,</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (res === <span class="literal">true</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`--- Gitalk 已经初始化 --- [ <span class="subst">${title}</span> ] `</span>);</span><br><span class="line"> initializedData.<span class="title function_">push</span>({id});</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Gitalk 初始化开始... [ <span class="subst">${title}</span> ] `</span>);</span><br><span class="line"> <span class="keyword">const</span> [e, r] = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">gitalkInitInvoke</span>({</span><br><span class="line"> id,</span><br><span class="line"> pathname,</span><br><span class="line"> title,</span><br><span class="line"> desc</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">if</span> (e || !r) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Error: Gitalk 初始化异常 [ <span class="subst">${title}</span> ] , 信息:`</span>, e || <span class="string">'无'</span>);</span><br><span class="line"> errorData.<span class="title function_">push</span>({</span><br><span class="line"> ...item,</span><br><span class="line"> <span class="attr">info</span>: <span class="string">'初始化异常'</span>,</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> successData.<span class="title function_">push</span>({</span><br><span class="line"> id,</span><br><span class="line"> });</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Gitalk 初始化成功! [ <span class="subst">${title}</span> ] `</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">''</span>); <span class="comment">// 空输出,用于换行</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'--------- 运行结果 ---------'</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">''</span>); <span class="comment">// 空输出,用于换行</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (errorData.<span class="property">length</span> !== <span class="number">0</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`报错数据: <span class="subst">${errorData.length}</span> 条。`</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(errorData, <span class="literal">null</span>, <span class="number">2</span>))</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`本次成功: <span class="subst">${successData.length}</span> 条。`</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 写入缓存</span></span><br><span class="line"> <span class="keyword">if</span> (config.<span class="property">enableCache</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`写入缓存: <span class="subst">${(initializedData.length + successData.length)}</span> 条,已初始化 <span class="subst">${initializedData.length}</span> 条,本次成功: <span class="subst">${successData.length}</span> 条。参考文件 <span class="subst">${config.cacheFile}</span>。`</span>);</span><br><span class="line"> <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">write</span>(config.<span class="property">cacheFile</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(initializedData.<span class="title function_">concat</span>(successData), <span class="literal">null</span>, <span class="number">2</span>));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`已初始化: <span class="subst">${initializedData.length}</span> 条。`</span>);</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">autoGitalkInit.<span class="title function_">start</span>(config.<span class="property">postsDir</span>).<span class="title function_">then</span>(<span class="function">() =></span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'end'</span>));</span><br></pre></td></tr></table></figure></div>
<h2 id="使用方式">使用方式</h2>
<h3 id="手动执行">手动执行</h3>
<h4 id="执行本地文件">执行本地文件</h4>
<ol>
<li>在项目根目录新增js文件 gitalk_init.js</li>
<li>执行命令</li>
</ol>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">GITHUB_REPOSITORY_OWNER=attson GITALK_TOKEN=<GITALK_TOKEN> node gitalk_init.js</span><br></pre></td></tr></table></figure></div>
<h4 id="或者使用-release-文件">或者使用 release 文件</h4>
<div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="code"><pre><span class="line">GITHUB_REPOSITORY_OWNER=attson GITALK_TOKEN=<GITALK_TOKEN> curl -sL https://raw.githubusercontent.com/attson/hexo-gitalk-init/v1.0.0/gitalk_init.js | node</span><br></pre></td></tr></table></figure></div>
<h3 id="github-workflows-中集成">github workflows 中集成</h3>
<h4 id="执行本地文件-2">执行本地文件</h4>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">GITALK_INIT</span></span><br><span class="line"> <span class="attr">run:</span> <span class="string">GITALK_TOKEN=${{</span> <span class="string">secrets.BUILD_GITHUB_IO_GITALK</span> <span class="string">}}</span> <span class="string">node</span> <span class="string">gitalk_init.js</span></span><br></pre></td></tr></table></figure></div>
<h4 id="或者使用-release-文件-2">或者使用 release 文件</h4>
<p>ci 中使用,推荐增加 md5 值校验</p>
<div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">GITALK_INIT</span></span><br><span class="line"> <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> if [[ $(wget https://raw.githubusercontent.com/attson/hexo-gitalk-init/v1.0.2/gitalk_init.js && cat gitalk_init.js | md5sum | cut -d ' ' -f 1) = "dec43e4fe531f8006bd0606a76a87973" ]]; then</span></span><br><span class="line"><span class="string"> GITALK_TOKEN=${{ secrets.BUILD_GITHUB_IO_GITALK }} node gitalk_init.js</span></span><br><span class="line"><span class="string"> else</span></span><br><span class="line"><span class="string"> echo "check md5 fail."</span></span><br><span class="line"><span class="string"> exit 1</span></span><br><span class="line"><span class="string"> fi</span></span><br></pre></td></tr></table></figure></div>
<h2 id="参数说明">参数说明</h2>
<table>
<thead>
<tr>
<th>字段</th>
<th>说明</th>
<th>默认值(env存在,则默认使用env的值)</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>username</td>
<td>GitHub repository 所有者 (必填)</td>
<td>process.env.GITHUB_REPOSITORY_OWNER</td>
<td>GitHub repository 所有者,可以是个人或者组织。对应Gitalk配置中的owner</td>
</tr>
<tr>
<td>repo</td>
<td>储存评论issue的github仓库名</td>
<td>process.env.GITALK_INIT_REPO <br/> || <code>${this.username}.github.io</code></td>
<td>储存评论issue的github仓库名,仅需要仓库名字即可。对应 Gitalk配置中的repo</td>
</tr>
<tr>
<td>token</td>
<td>GitHub 的 Personal access token (必填)</td>
<td>process.env.GITALK_TOKEN</td>
<td>从 GitHub 的 <a class="link" href="https://github.com/settings/tokens" >Personal access tokens<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 页面,点击 <a class="link" href="https://github.com/settings/tokens/new" >Generate new token<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></td>
</tr>
<tr>
<td>enableCache</td>
<td>是否启用缓存</td>
<td>process.env.GITALK_INIT_CACHE || true</td>
<td>是否启用缓存,启用缓存会将已经初始化的数据写入配置的 outputCacheFile 文件,下一次直接通过缓存文件 outputCacheFile 判断</td>
</tr>
<tr>
<td>cacheFile</td>
<td>缓存文件输出的位置</td>
<td>process.env.GITALK_INIT_CACHE_FILE <br/> || path.join(__dirname, ‘./public/gitalk-init-cache.json’)</td>
<td></td>
</tr>
<tr>
<td>cacheRemote</td>
<td>获取缓存的远程地址</td>
<td>process.env.GITALK_INIT_CACHE_REMOTE <br/> || <code>https://${this.repo}/gitalk-init-cache.json</code></td>
<td>只用于获取缓存的来源,缓存仍然会写到 cacheFile. 读取优先级 cacheFile > cacheRemote. 故cacheFile文件存在时,忽略 cacheRemote</td>
</tr>
<tr>
<td>postsDir</td>
<td>hexo posts 文件路径</td>
<td>process.env.GITALK_INIT_POSTS_DIR <br/> || ‘source/_posts’</td>
<td></td>
</tr>
</tbody>
</table>
<ol>
<li>所有参数支持使用环境变量配置 (推荐)</li>
<li>所有参数支持使用自定义的 gitalk_init.json 文件
<ul>
<li>配置文件中value支持环境变量占位 </li>
</ul>
</li>
</ol>
<div class="code-container" data-rel="Json"><figure class="iseeu highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"username"</span><span class="punctuation">:</span> <span class="string">"attson"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"token"</span><span class="punctuation">:</span> <span class="string">"{{process.env.GITALK_TOKEN}}"</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure></div>
]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>example</tag>
<tag>hexo</tag>
</tags>
</entry>
<entry>
<title>基于 Golang 泛型实现的简单容器</title>
<url>/p/golang-container-base-genericity.html</url>
<content>< any {</span><br><span class="line"> return Test{</span><br><span class="line"> Name: "test",</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line">// 通过容器构建实例</span><br><span class="line">v1 := container.Make[Test]()</span><br><span class="line">println(v1.Name) // test</span><br></pre></td></tr></table></figure></div>
<h3 id="为结构体指针注册一个构建函数">为结构体指针注册一个构建函数</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 为结构体指针注册一个构建函数</span><br><span class="line">container.Register[*Test](func() any {</span><br><span class="line"> return &Test{</span><br><span class="line"> Name: "test_pointer",</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line">// 通过容器构建实例</span><br><span class="line">v2 := container.Make[*Test]()</span><br><span class="line">println(v2.Name) // test_pointer</span><br></pre></td></tr></table></figure></div>
<h3 id="为接口注册一个构建函数">为接口注册一个构建函数</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 为接口注册一个构建函数</span><br><span class="line">container.Register[I](func() any {</span><br><span class="line"> return Test{</span><br><span class="line"> Name: "test_interface",</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line">// 通过容器构建实例</span><br><span class="line">v3 := container.Make[I]()</span><br><span class="line">println(v3.Key()) // test_interface</span><br></pre></td></tr></table></figure></div>
<h3 id="在容器中设置一个实例-单例">在容器中设置一个实例(单例)</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 在容器中设置一个实例(单例)</span><br><span class="line">container.Set[Test](Test{</span><br><span class="line"> Name: "test_set",</span><br><span class="line">})</span><br><span class="line">// 通过容器获取实例</span><br><span class="line">v4 := container.Get[Test]()</span><br><span class="line">println(v4.Name) // test_set</span><br><span class="line"> </span><br></pre></td></tr></table></figure></div>
<h3 id="在容器中设置一个指针实例">在容器中设置一个指针实例</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 在容器中设置一个指针实例</span><br><span class="line">container.Set[*Test](&Test{</span><br><span class="line"> Name: "test_pointer_set",</span><br><span class="line">})</span><br><span class="line">// 通过容器获取实例</span><br><span class="line">v5 := container.Get[*Test]()</span><br><span class="line">println(v5.Name) // test_pointer_set</span><br></pre></td></tr></table></figure></div>
<h3 id="在容器中设置一个接口实例">在容器中设置一个接口实例</h3>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 在容器中设置一个接口实例</span><br><span class="line">container.Set[I](Test{</span><br><span class="line"> Name: "test_interface_set",</span><br><span class="line">})</span><br><span class="line">// 通过容器获取实例</span><br><span class="line">v6 := container.Get[I]()</span><br><span class="line">println(v6.Key()) // test_interface_set</span><br></pre></td></tr></table></figure></div>
<h2 id="总结">总结</h2>
<p>总体使用起来简单了很多,这里针对比较复杂的业务项目,需要抽象实现分离等规范的项目</p>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>golang</tag>
</tags>
</entry>
<entry>
<title>如何快速学习一门新编程语言</title>
<url>/p/how-to-learn-a-new-program-language.html</url>
<content><![CDATA[<h2 id="概述">概述</h2>
<p>笔者目前工作已有6个年头,接触过PHP、golang、java/kotlin、js/ts、.net等,对这几个语言都有一些项目开发经验,最早是在php上扎根。本文谈谈自己对新语言学习方向的一些看法。</p>
<h2 id="学习方向">学习方向</h2>
<h3 id="语法">语法</h3>
<p>大多数语言的语法结构和思想,基本是和c语言相似的,包含<strong>变量声明,类型定义,结构体/类,定义,分支条件,循环结构等</strong>。所以当你熟悉一门语言之后,再去看其他语言的代码,基本都是能看懂的。千万不要有固有思想,认为我只会php,去看js就一点都看不下去,这种心理上的矛盾,会让你在学习新语言的路上难度提升。</p>
<p>当然每个语言有一定特有的语法糖,比如 go 的 defer,kotlin 的各种魔法函数,这些其实不是特别重要,前期只要知道有这么个东西和它的作用就可以了。</p>
<h3 id="常用的包">常用的包</h3>
<p>每个语言都有自己的内置函数和标准库,在项目中常用的有<strong>字符串处理,数组处理,集合处理,日志库,序列化库,配置管理,文件读写,类型转换</strong>,熟悉这些基本库,对上手开发是比较有帮助的,毕竟真实项目很难离开这些。</p>
<p>进阶的库可以有所了解,比如<strong>网络io处理,反射,信号处理等</strong>,这些基本会在较为底层的开发领域会遇到,基本了解即可</p>
<h3 id="开发框架">开发框架</h3>
<p>一个复杂的项目,很难离开开发框架,使用这些框架,能够帮助我们快速搭建一个规范成熟的项目。通过常用框架去入门和熟悉一门语言,也是一个好的方式。<br>
比如java的spring系列,php的laravel系列,js的vue/react系列。当然前端还分为ui框架,目前国内常用的elementui,在web项目里面就比较常见。</p>
<p>在公司开发项目,基本都会选择一个合适的框架,提升开发效率和方便技术管理。</p>
<h3 id="中间件">中间件</h3>
<p>一个项目通常都会与其他组件一起协作,不同语言与组件的交互,会有不同的客户端程序,比如mysql在java中的jdbc,mybatis,在php中的pdo,laravel-orm,都是一个常规项目所需要和选择的。<br>
一般的后端项目会涉及如<strong>mysql、redis、mongodb、rabbitmq等</strong>,后端大多数都是与数据进行交互,所以数据相关的中间件需要熟悉。</p>
<h3 id="包管理器">包管理器</h3>
<p>成熟的项目同样离不开包管理器。在项目实际开发中,会运用到大量的第三方库,通过使用这些第三方优质的库,能够大大减少我们的开发时间,所以如何去导入和版本控制,<br>
是每个项目都需要考虑的。比如php中使用composer管理,java中有grade/maven,js中有npm、yarn、pnpm。不同的管理器,会有不同的优化点,这个也是需要去了解如何使用的。</p>
<h3 id="构建部署">构建部署</h3>
<p>目前构建打包基本都是和包管理器绑定的,通过包管理器命令,就可以将可运行的项目包构建出来,当然像php这样的脚本语言,代码文件本身就可以直接运行,也没有打包这层概念。<br>
不同的语言的部署方式会有较大的差异,比如前端项目通常部署在oss文件服务中,后端项目可以部署在主机上,也可以使用容器化技术部署,还需要考虑机器资源,参数调优等问题。</p>
<h3 id="进阶">进阶</h3>
<p>完成上述方向学习后,进阶方向还可以熟悉该语言的<strong>编译运行,线程模型,内存模型,设计思想等</strong>,加强对该语言的理解。</p>
<h2 id="总结">总结</h2>
<p>在已经有编程语言的基础上去学习一门新语言,通常是比较容易的,最难的我认为还是<strong>摆脱个人的偏见</strong>,比如php是世界上最好的语言。<br>
当思想固化之后,就很难接受新的东西了,每个语言都有它的优缺点,请勿将自己牢牢定位在xxx语言工程师,路不要走窄了~</p>
<h2 id="谈谈对多语言开发者的想法">谈谈对多语言开发者的想法</h2>
<p>最后在谈谈对多语言开发者的想法,从个人的应聘和面试经验来看,面试官还是倾向于应聘者只在一门语言上精通。一个有php一年+java一年的经验,另一个有java两年的经验,在java工程师面试上,<br>
毋庸置疑的是后者更占优势。至少在当前工作环境下,公司对语言开发岗位的定位通常是比较明确的。</p>
<p>从个人对技术理解的方向来看,程序员的价值应该在设计模式,领域建模,网络通信等通用的技能。语言只是个工具,熟悉多门语言的设计思想,是能够让开发者跳出基础开发的瓶颈的。所以在有机会的情况下,<br>
学习多门语言总不是一件坏事情,当然为了保住当前的饭碗,请不要放弃在主语言上持续学习。</p>
]]></content>
<tags>
<tag>learn</tag>
</tags>
</entry>
<entry>
<title>linux 系列更换软件源</title>
<url>/p/linux-source-mirror-change.html</url>
<content><![CDATA[<h3 id="1-ubuntu-阿里云源">1. ubuntu-阿里云源</h3>
<h4 id="要注意-etc-apt-sources-list-默认的是什么">要注意/etc/apt/sources.list 默认的是什么</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line"># grep -Ev "^$|[#]" 过滤掉空行和#开头的</span><br><span class="line">cat /etc/apt/sources.list | grep -Ev "^$|#"</span><br></pre></td></tr></table></figure></div>
<p><img
lazyload
src="/images/loading.svg"
data-src="./linux-source-mirror-change/source-list.png"
alt="list"
></p>
<p>看到域名都是 <code>cn.archive.ubuntu.com</code>; 可以手动将这些都改成阿里云的源 <code>mirrors.aliyun.com</code><br>
也可以通过下面的命令直接替换</p>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 万事先备份</span><br><span class="line">cp /etc/apt/sources.list /etc/apt/sources.list.bk</span><br><span class="line">sed -i s/cn.archive.ubuntu.com/mirrors.aliyun.com/g /etc/apt/sources.list</span><br><span class="line"># 验证一波</span><br><span class="line">cat /etc/apt/sources.list | grep -Ev "^$|#"</span><br></pre></td></tr></table></figure></div>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>linux</tag>
</tags>
</entry>
<entry>
<title>mac php + xdebug安装</title>
<url>/p/mac-php-xdebug.html</url>
<content><![CDATA[<h1>mac php + xdebug安装</h1>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">背景:之前用的自带php 配置的xdebug,突然发现不能用了,error.log 也不记录在之前的日志文件里了</span><br><span class="line">查看php -v 成了7.1 的了,一脸xx</span><br><span class="line"></span><br><span class="line">最后进/usr/bin 看,php确实变成了7.1</span><br><span class="line">/ect 下面之前配置的php.ini 也不见了</span><br><span class="line">最后在查问题时,看到一篇https://www.cnblogs.com/ailhc/p/7398479.html,提到mac在系统更新</span><br><span class="line">时候,会将自带的配置给还原</span><br><span class="line">然后便想到,放弃自带php,再见</span><br></pre></td></tr></table></figure></div>
<h4 id="首先">首先</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">//因为自带的php可能其他地方会用到,就不删除了,重新装一个</span><br><span class="line">brew update</span><br><span class="line">brew search php</span><br><span class="line">brew install php71</span><br><span class="line"></span><br><span class="line">安装后查看下php -v php-fpm -v 是不是最新的7.1.11 mac最新自带 7.1.7</span><br><span class="line">如果不是查看环境变量</span><br><span class="line">echo $PATH </span><br><span class="line">看看/usr/local/bin/和/usr/local/sbin 是不是写在/usr/bin和/usr/sbin之前</span><br><span class="line">没有则添加,不是则修改</span><br></pre></td></tr></table></figure></div>
<h4 id="安装个php-version-有需要安装多版本的可以安装">安装个php-version(有需要安装多版本的可以安装)</h4>
<div class="code-container" data-rel="Php"><figure class="iseeu highlight php"><table><tr><td class="code"><pre><span class="line">brew install php-version</span><br><span class="line">source $(brew --prefix php-version)/php-version.sh && php-version</span><br><span class="line">php-version 查看当前安装的版本(自带的是看不到的?)</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 只能在当前终端有效, 新切换的终端输入php -v不变,但是我们只要在切换过的终端,</span></span><br><span class="line"><span class="comment"> * 启动php-fpm,后台运行的就是切换后的fpm。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">php-version <span class="number">7.1</span>.<span class="number">11</span> <span class="comment">//更换版本</span></span><br></pre></td></tr></table></figure></div>
<h4 id="配置php-php-fpm">配置php php-fpm</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">//brew 安装的php,配置文件在/usr/loacl/etc/php</span><br><span class="line">cd /usr/loacl/etc/php</span><br><span class="line">//找到对应的版本</span><br><span class="line">cd 7.1</span><br><span class="line">//vim php.ini 没有则增加</span><br><span class="line">display_errors = off //不显示错误信息(不输出到页面或屏幕上)</span><br><span class="line">log_errors = On</span><br><span class="line">error_log = "/usr/local/lnmp/php/var/log/error_log"(自定义,绝对路径)</span><br><span class="line">error_reporting=E_ALL</span><br><span class="line">date.timezone = PRC</span><br><span class="line"></span><br><span class="line">//vim php-fpm.conf 没有则增加</span><br><span class="line">catch_workers_output = yes</span><br><span class="line">error_log = "/usr/local/lnmp/php/var/log/error_log"(自定义,绝对路径)</span><br><span class="line"></span><br><span class="line">//注意!</span><br><span class="line">php_admin_value[error_log]参数会覆盖php.ini中的error_log 参数</span><br><span class="line"></span><br><span class="line">最终按phpinfo 里的error_log配置为准</span><br></pre></td></tr></table></figure></div>
<h4 id="启动php-fpm">启动php-fpm</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">php-fpm -v 先查看是不是要启动的版本</span><br><span class="line">sudo php-fpm</span><br><span class="line"></span><br><span class="line">//出现问题 php-fpm 并不在后台运行</span><br><span class="line">终端输出</span><br><span class="line">NOTICE: fpm is running, pid 42540</span><br><span class="line">NOTICE: ready to handle connections</span><br><span class="line"></span><br><span class="line">结束php-fpm</span><br><span class="line">sudo killall php-fpm</span><br><span class="line">修改php-fpm.conf</span><br><span class="line">daemonize = yes (如果设置为no, fpm会运行在前台)</span><br><span class="line">再启动</span><br><span class="line"></span><br><span class="line">在页面输出phpinfo()查看配置</span><br></pre></td></tr></table></figure></div>
<h4 id="安装Xdebug">安装Xdebug</h4>
<p>寻找对应php版本的xdebug版本</p>
<ol>
<li>
<p>先将info输出到一个文件<br>
php -i > info.txt</p>
</li>
<li>
<p>打开info.txt 复制所有内容</p>
</li>
<li>
<p>打开寻找合适xdebug的页面https://xdebug.org/wizard.php</p>
</li>
<li>
<p>将刚才复制的内容粘贴至提供的输入框中 点击Analyse my phpinfo() output 就会显示下载安装步骤,<br>
跟着一步步执行就好了</p>
</li>
</ol>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">出现问题 配置之后php -v | php -m 显示</span><br><span class="line">Zend OPcache requires Zend Engine API version 220090626.</span><br><span class="line">The Zend Engine API version 220100525 which is installed, is newer.</span><br><span class="line">Contact Zend Technologies at http://www.zend.com/ for a later version of Zend OPcache.</span><br><span class="line"></span><br><span class="line">解决办法,重新配置xdebug,删除之前的xdebug.so(移动过去的那个) 和 xdebug文件夹,</span><br><span class="line">重新解压</span><br><span class="line">按照上面执行步骤,在执行phpize 时候,使用绝对路径,php所在的路径 </span><br><span class="line">/usr/local/Cellar/php71/7.1.11_22/bin/phpize</span><br></pre></td></tr></table></figure></div>
<h4 id="配置xdebug">配置xdebug</h4>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">xdebug.remote_enable = 1</span><br><span class="line">xdebug.remote_handler = "dbgp"</span><br><span class="line">xdebug.remote_host = "127.0.0.1"</span><br><span class="line">xdebug.remote_port = 9001 </span><br><span class="line">xdebug.remote_log = "/var/log/php-fpm/xdebug.log"</span><br></pre></td></tr></table></figure></div>
<h4 id="参考文章">参考文章</h4>
<ul>
<li>
<p>php error_log配置 <a class="link" href="http://www.jb51.net/article/31499.htm" >http://www.jb51.net/article/31499.htm<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
</li>
<li>
<p>php-fpm 配置详解 <a class="link" href="https://www.cnblogs.com/jonsea/p/5522018.html" >https://www.cnblogs.com/jonsea/p/5522018.html<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
</li>
<li>
<p>php-version 安装 <a class="link" href="http://www.jianshu.com/p/bee30e411b00" >http://www.jianshu.com/p/bee30e411b00<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
</li>
<li>
<p>xdbug配置 <a class="link" href="https://www.awaimai.com/1290.html" >https://www.awaimai.com/1290.html<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> <a class="link" href="https://www.cnblogs.com/purelightme/p/6605648.html" >https://www.cnblogs.com/purelightme/p/6605648.html<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>
</li>
</ul>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>example</tag>
<tag>php</tag>
</tags>
</entry>
<entry>
<title>在macos下使用virtual-box安装ubuntu server</title>
<url>/p/macos-vbox-ubuntu.html</url>
<content><![CDATA[<h2 id="使用版本">使用版本</h2>
<div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">MacOs Catalian 10.15.6</span><br><span class="line">VirtalBox 6.1.16</span><br><span class="line">Ubuntu Server ubuntu-20.04.1-live-server-amd64.iso</span><br></pre></td></tr></table></figure></div>
<h2 id="一、安装VirtualBox">一、安装VirtualBox</h2>
<h3 id="下载">下载</h3>
<ul>
<li>下载地址: <a class="link" href="https://www.virtualbox.org/wiki/Downloads" >https://www.virtualbox.org/wiki/Downloads<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 国内下载比较慢,推荐借助神秘力量</li>
</ul>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603375584584.jpg"
alt="download-vbox"
></p>
<ul>
<li>不要忘记检查一下sha256值 <a class="link" href="https://www.virtualbox.org/download/hashes/6.1.16/SHA256SUMS" >https://www.virtualbox.org/download/hashes/6.1.16/SHA256SUMS<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="code"><pre><span class="line">shasum -a 256 VirtualBox-6.1.16-140961-OSX.dmg</span><br><span class="line">d7df0f05d9a9e7cba50ea01da264ac20948b1c9c0e0cccd2d628085c9f434d45 VirtualBox-6.1.16-140961-OSX.dmg</span><br></pre></td></tr></table></figure></div>
</li>
</ul>
<h3 id="安装">安装</h3>
<ul>
<li>
<p>像正常安装软件一样即可</p>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603376858313.jpg"
alt="install-vbox"
></p>
</li>
<li>
<p>相关需要的权限都给</p>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603377152373.jpg"
alt="install-vbox"
></p>
</li>
</ul>
<h2 id="二、安装ubuntu-server">二、安装ubuntu server</h2>
<h3 id="下载ubuntu-server">下载ubuntu server</h3>
<ul>
<li>下载地址: <a class="link" href="https://ubuntu.com/download/server" >https://ubuntu.com/download/server<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li>
</ul>
<h3 id="安装ubuntu-server">安装ubuntu server</h3>
<h4 id="Step-1-打开VirBox,点击新建">Step 1. 打开VirBox,点击新建</h4>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603377642251.jpg"
alt="install-ubuntu1"
></p>
<h4 id="Step-2-配置基础信息和内存">Step 2. 配置基础信息和内存</h4>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603377649152.jpg"
alt="install-ubuntu2"
></p>
<h4 id="Step-3-配置虚拟硬盘">Step 3. 配置虚拟硬盘</h4>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/1603377652616.jpg"
alt="install-ubuntu3"
></p>
<h4 id="Step-4-点击存储,添加盘片-设置镜像文件">Step 4. 点击存储,添加盘片(设置镜像文件)</h4>
<p><img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/iso1.jpg"
alt="install-ubuntu4-1"
><br>
<img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/iso2.jpg"
alt="install-ubuntu4-2"
></p>
<h4 id="Step-5-启动">Step 5. 启动</h4>
<ul>
<li>
<p>. 注意,在某些版本下会出现启动时如下的崩溃信息,是因为没有给virtual-box 授权音频输出权限的问题,可以通过[ 设置->声音->取消声音 ]解决<br>
<a class="link" href="https://unix.stackexchange.com/questions/609077/how-to-fix-virtualbox-vm-quit-unexpectedly-when-running-my-ubuntu-20-04-lts-vm" >参考解决方案<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br>
<img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/bug1.jpg"
alt="install-ubuntu5-1"
></p>
</li>
<li>
<p>点击启动即可开始安装ubutnu server</p>
</li>
</ul>
<h2 id="三、其他">三、其他</h2>
<h3 id="从主机访问虚拟机">从主机访问虚拟机</h3>
<p>virtual box 默认的网卡 是网络网址转换(NAT) 模式</p>
<ol>
<li>
<p>通过配置端口转发<br>
<img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/nat1.jpg"
alt="install-nat-1"
><br>
<img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/nat2.jpg"
alt="install-nat-2"
></p>
</li>
<li>
<p>可以通过修改模式为桥接网卡, 让主机和虚拟机在同一网段, 就能够直接通过虚拟机的ip访问了<br>
<img
lazyload
src="/images/loading.svg"
data-src="./macos-vbox-ubuntu/bridge.jpg"
alt="install-bridge"
></p>
</li>
</ol>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>