12 Commits

Author SHA1 Message Date
github-actions[bot]
03be85005c chore: lint text and auto correct 2025-09-18 18:36:50 +08:00
github-actions[bot]
4373e3ed64 Change img CDN URL 2025-09-18 18:36:16 +08:00
93f0c2110b fix: js asset cdn not working, using new cdn provider 2025-09-17 23:13:34 +08:00
9e72f30ff4 feat: new post 2025-09-17 23:02:03 +08:00
github-actions[bot]
f718df5a11 chore: lint text and auto correct 2025-06-23 19:40:48 +08:00
ad8fbc6fc2 Update 个人向Linux新服务器初始化清单.md 2025-06-23 19:40:32 +08:00
d2368e9008 feat: update post 2025-06-21 16:17:57 +08:00
dependabot[bot]
c0e9369ebf build(deps): bump actions/deploy-pages from 1 to 4
Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 1 to 4.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v1...v4)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 20:05:19 +08:00
dependabot[bot]
0f95c8de33 build(deps): bump actions/configure-pages from 2 to 5
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 2 to 5.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](https://github.com/actions/configure-pages/compare/v2...v5)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 20:05:11 +08:00
dependabot[bot]
767e3ae8a5 build(deps): bump actions/upload-pages-artifact from 1 to 3
Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 1 to 3.
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 18:51:40 +08:00
github-actions[bot]
b7d529f579 chore: lint text and auto correct 2025-06-15 18:49:28 +08:00
b1565d9c3e feat: update article 2025-06-15 18:44:09 +08:00
6 changed files with 228 additions and 33 deletions

View File

@@ -42,7 +42,7 @@ jobs:
submodules: recursive
- name: Setup Pages
id: pages
uses: actions/configure-pages@v2
uses: actions/configure-pages@v5
- name: Build with Hugo
env:
# For maximum backward compatibility with Hugo modules
@@ -53,7 +53,7 @@ jobs:
--minify \
--baseURL "/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v3
with:
path: ./public
@@ -67,4 +67,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v4

View File

@@ -0,0 +1,128 @@
---
title: LLM Agent is All You Need - 当我用大模型助手来指导我完成 MVP 产品 - 「Colin's Weekend Project」
date: 2025-09-14
description: 我个人喜欢挑一个周末在一个很短很专注的时间内,捣鼓点小玩意。这个栏目用来记录我的这些 idea、作品、创作过程以及吐槽。今天来挑战一下在大模型的指导下完成一个最小可行产品 (MVP)
categories:
- Weekend Project
tags:
- 技术
- JAMStack
- LLM
- AI
---
> **「Colin's Weekend Project」**
> 我个人喜欢挑一个周末在一个很短很专注的时间内,捣鼓点小玩意。这个栏目用来记录我的这些 idea、作品、创作过程以及吐槽
今天来挑战一下,在大模型的指导下,完成一个最小可行产品 (MVP)
## idea
如果单纯是开发一个完整的 web 程序 or 移动端程序,其实没啥意思。我之前已经搞过很多,更别提日常在公司里面就是在开发各种功能。今天我打算以一个非专业人士的视角,探究一下:
- 当下各种 AI 助手已经百花齐放,飞入寻常百姓家。但是当下的 AI 在真实世界的任务中,究竟能做到什么地步
- 如果作为一名非专业人士,究竟能不能借助这些 AI 工具做出一个可用的产品
- 如果真正要做一个面向 C 端的产品,把流程 Run 起来持续下去,需要考虑哪些因素
## 如果一切都从 LLM 开始...
我需要代入一个非专业开发人员的视角,来进行这次的项目。首先项目启动的第一个问题:在没有任何产品经理的知识,不懂得产品开发流程的小白的情况下,我需要如何开始?
在没有 LLM 以前,或许我需要先各种查阅资料学习,或者各种摇人让懂行的朋友进行指导。但是现在,一切都不一样了:随便一个 LLM 都可以帮我快速入门
一开始,我是打算接住 LLM 让我快速了解产品相关的知识。但是突然觉得,既然都用 AI 了,为什么还在遵循原有的路径,一步步自己学习、理解然后教 AI 做事呢换个思路我只要提供需求AI 来拆解任务。
于是
![image|476x415](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249632.png)
![image-1|700x472](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249633.png)
![image-2|700x472](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249634.png)
利用 AI 生成一套提示词,来指导我如果分析我的需求、拆解任务
不得不说,对于这些跨领域的知识,能有一个不厌其烦的 AI 助手来循序渐进地跟你交流、帮你分析,效果非常好。人类可能还真不好干这个活。
## 「AI 教我做产品」
经过跟这个「MVP 导师」的 LLM Agent 反复沟通,确定了产品的主要构想和核心事项。以下是摘录的一部分
```markdown
#### MVP 概要3句话
- **为谁**2030 岁、周末感到无聊且有意愿尝试新事物的年轻人。
- **解决什么痛点**:不清楚该尝试哪些活动、如何快速入门、活动是否适合自己、以及能获得什么收益。
- **提供的核心功能**:活动列表页面 → 点击感兴趣的活动 → 展示入门门槛与材料推荐(入门材料按钮)并埋点上报。
```
```markdown
## MVP 核心功能:
1. **活动列表**:集中展示多种可入门活动(绘画、球类、手工等)。
2. **入门详情**:点击任意活动 → 展示入门门槛、必备材料、推荐教程链接。
3. **埋点追踪**:记录“点击 → ≥1min 外部阅读 → 回站”行为,用于验证假设。
```
这里印象深刻的是MVP 导师让我先确保用户痛点一定要是真实的在初期没有论证的情况下MVP 的意义就在于基于一个假设 (假设用户的痛点是 xxx), 我们要围绕这个痛点先开发出 1-2 个核心功能,然后通过用户数据分析,来验证我们关于用户痛点的假设是否成立。如果不成立说明是伪需求,也就没有继续投入的必要了。
这一点还是让我挺惊喜的,因为大部分人有个 idea 想做 xx 产品,大部分都是脑门一热,想要有 xxx 功能但是其实根本的需求并不是这个。花了很多精力搞出来的功能其实是伪需求。而 AI 导师专业水准还是挺在线的,能够在一开始就识别这个风险
## Vibe Coding
接下来就是要进入开发的部分了。我选择的 AI 代码工具是字节的 Trae 海外版,不用验证手机号而且可以使用 Google Gemini、OpenAI GPT-4o、Anthropic Claude 4 等高级模型。
首先让 AI 根据产品需求文档、拆解任务文档,确定了技术方案。不过这里我为了效率简化了下&注入了一些自己的私房调料,最终使用的方案为:
- astro + vue3 + tailwind css 来构建 web 站点
- directus cms 作为后端,省去编写后端和对接数据库的麻烦
- vercel 快速部署
这部分没啥好说的,简单列几个吐槽的点吧:
- astro 配置 tailwindcss, 换了一圈大模型没一个正确的。应该是跟近期大版本更新有关系。最后还是我手动跟着 astro 官方的文档搞定的
- trae 高级模型试用额度很低,没写几个功能就超限了开始排队,动不动前面几百号人基本没法用
- 现阶段 AI IDE 基本都是基于 vs code 改的。所以 vscode 的缺点也都一并继承了过来,很多语言的插件需要额外手动安装、各种变量跳转用不了、各种奇怪的波浪线报错又没法快速修正
最后简要看下最终的成果吧
![image-3](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249635.png)
![image-4](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249636.png)
后台数据:
![image-5](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249637.png)
## 埋点上报与用户行为分析
之前做的都是玩具项目和公司内部平台,没怎么接触过 C 端用户行为分析。这块确实还是个挺陌生的领域。不过好在我们有万能的 AI. 在经过埋点需求分析、技术方案对比、任务拆解之后,最后采用了 Umami 平台来进行上报,并简单配置了下指标用于计算用户停留,辅助验证我们关于用户痛点的假设
![image-6|0x0](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249639.png)
跟 MVP 导师沟通的时候,确定了验证假设的方式为:衡量用户是否点击「查看详情」按钮
- 用户点击并在外部阅读 ≥1 分钟后回站
- 成功阈值25% 的访问者完成“点击 → ≥1min 回站
为了方便统计,借助 umaimi 的统计功能快速实现,我只需要统计有多少比例的用户至少点击了一次「了解详情」. 具体到代码实现上,就是在「点击详情」按钮添加一个上报,上报内容包括用户的 session id, 后面在 umaimi 统计一段时间内,按钮点击事件里面,有多少独立的 session id 处以总的 uv 就可以。
![image-7](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249640.png)
## 投放
众所周知,天朝桌面端 web 用户已经约等于 0 了技术博客都很少人看更别提这种泛娱乐向的内容。MVP 导师提供的方案,也是路线正确,但是 web 端用户数据反馈验证的路子基本没用。不过这个 web 页面我也不指望能成为流量主力,最多算个 wiki.
要想真的有人看,收获真实用户反馈,还是需要到各种新媒体平台去投放的。然后再收集数据进行分析,不过这个工作量就是另外一回事了。运营起来还是需要挺多时间精力的。
尝试做了几个图投放到小红书,放几个示例图
![image-8](https://blog-1301127393.file.myqcloud.com/BlogImgs/202509172249641.png)
用的搞定设计的模版调整了下,插图是用 Gemini, 效果还可以,能很好地遵循用户指令,不过美学方面跟 MidJourney 那些还是差了一截,毕竟人家专攻的方向。提示词里面限制好风格的话出图效果还是可以的,这里后续如果有必要的话,其实也可以 AI 批量生产插图。
不过小红书账号冷启动,反响平平。这里后续有时间再研究吧
## The End

View File

@@ -1,6 +1,7 @@
---
title: 个人向 Linux 新服务器初始化清单
date: 2023-03-14
lastmod: 2025-06-21
description: 一份 Linux 初始化清单,避免每次拿到新的服务器都要一个个去各种地方搜集指令,以做备忘 & 供有需要的朋友参考。以目前最新的 Debian 11 Bullseye 为例
categories:
- 技术
@@ -8,16 +9,14 @@ tags:
- 技术
- Linux
- Debian
- Traefik
- Headless CMS
---
一份 Linux 初始化清单,避免每次拿到新的服务器都要一个个去各种地方搜集指令,以做备忘 & 供有需要的朋友参考。
服务器发行版我个人推荐 Debian 系列CentOS 系现在已经开始分裂而且说实话对新手其实并不友好。Debian 是在兼容性,易用性和稳定性之间都取得不错平衡的发行版。新手推荐 Ubuntu, 不过最近商业化有点过度,夹带了越来越多的私活,我个人所有新安装的 Linux 已经全线转向 Debian. 下文以目前最新的 Debian 11 Bullseye 为例
服务器发行版我个人推荐 Debian 系列CentOS 系现在已经开始分裂而且说实话对新手其实并不友好。Debian 是在兼容性,易用性和稳定性之间都取得不错平衡的发行版。新手推荐 Ubuntu, 不过最近商业化有点过度,夹带了越来越多的私活,我个人所有新安装的 Linux 已经全线转向 Debian. 下文以目前最新的 Debian 11 Bullseye 为例。Debian 12 bookworm 也测试通过。
> azure 干净的 debian 11 镜像,资源使用情况供参考
> azure 干净的 debian 11 镜像,资源使用情况供参考
>
> ~1G Disk, ~100M RAM, ~300 packages
@@ -32,12 +31,15 @@ tags:
检查服务商防火墙和系统自带防火墙 (debian 系一般为 `ufw`, cent os 系一般为 `firewall-cmd`).放行 SSH(22), 新的 SSH(自定义), HTTP, HTTPS, 以及其他常用开发端口
### 1.2 新建用户与检查 sudoer
登录到 root 用户,创建个人账户并设定密码
```shell
// -m 创建对应home文件夹
// 添加到 sudo 用户组自动获得sudo权限, 部分发行版为wheel组
useradd -m --groups sudo colin
// 设定密码
passwd colin
```
也可直接编辑`/etc/sudoers` 文件为新用户添加 sudo 权限,使用 `visudo` 指令可以自动帮你校验,避免配置写错把系统搞崩
@@ -54,7 +56,6 @@ useradd -m --groups sudo colin
//for debian
sudo sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
//for ubuntu
sudo sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list
```
@@ -73,7 +74,8 @@ sudo apt install zsh tmux htop duf htop tldr screenfetch tree
### 1.4 SSH 安全
修改端口,配置文件`/etc/ssh/sshd_config`. 重启机器或 sshd 服务后生效
修改端口,配置文件`/etc/ssh/sshd_config`. 重启机器或 sshd 服务后生效
此外最好将`PermitRootLogin`修改为`no`, 可以禁用 root 登录。
在本机检查`~/.ssh/`有无 id_rsa 等已生成的 key. 如没有再使用 `ssh-keygen` 生成私钥
将本机的公钥上传到远端,再写入远端的 `authorized_keys`
@@ -83,12 +85,10 @@ sudo apt install zsh tmux htop duf htop tldr screenfetch tree
注意修改权限,`~/.ssh/authorized_keys` 权限为 600. `~/.ssh/`为 700
可以参考以下设置
> .ssh/ 0700/rwx------
> .ssh/*.pub 644/rw-r--r--
> .ssh/* 0600/rw-------
如失败可参考这篇文章 debug. [https://superuser.com/questions/1137438/ssh-key-authentication-fails](https://superuser.com/questions/1137438/ssh-key-authentication-fails)
### 1.5 设置 hostname
@@ -100,18 +100,18 @@ sudo hostnamectl set-hostname my-new-server
sudo hostnamectl status
```
此外`/etc/hosts` 中默认会有个本机 hostname 映射到`127.0.0.1` 的配置,修改 host 之后这里别名的映射也要修改下,不然终端执行命令会一直弹 `sudo: unable to resolve host xxx: Name or service not known`
修改后需重启
---
### 1.6 SWAP
可选,建议内存<2G 配置 swap, 大小至少为 2 倍物理内存
可选,建议内存<2G 配置 swap, 大小至少为 2 倍物理内存可以有效避免意外爆内存的情况仅推荐 SSD 盘的服务器开启
推荐用 `fallocate` , 因为这个是最简单最快速的创建交换空间的方法 `fallocate`  命令用于为文件预分配块 / 大小
以下内容参考 linux.cn
使用  `fallocate`  创建交换空间首先在  `/`  目录下创建一个名为  `swap_space`  的文件然后分配 2GB  `swap_space`  文件
```shell
@@ -132,8 +132,6 @@ sudo swapon -s
```
每次重启后都要重新挂载磁盘分区因此为了使之持久化就像上面一样我们编辑  `/etc/fstab`  并输入下面行
```
@@ -146,9 +144,6 @@ sudo swapon -s
还可以按需选择使用 zram提升内存可用量不过会略微增加 cpu 使用和内存延时可以搜索 zramctl, zramswap 等关键字
注意 Debian 新版本 swapon 等工具所在的目录 /usr/sbin 不在普通用户的 PATH 可能需要手动执行前缀使用 /usr/sbin/swapon
---
### 1.7 绑定域名  
@@ -200,7 +195,7 @@ docker mirror 配置可以加速 image pull, 国内公开可用的加速站点
],
"log-opts": {
"max-file": "5",
"max-size": "10m"
"max-size": "1m"
}
}
```
@@ -290,12 +285,14 @@ sudo systemctl enable fail2ban
```conf
[sshd]
enabled = true
port = 20000 # 这里修改为实际的 sshd 端口
# 这里修改为实际的 sshd 端口
port = 20000
filter = sshd
banaction = iptables-allports
[DEFAULT]
findtime = 3600 # 1h 时间窗口
# 1h 时间窗口
findtime = 3600
maxretry = 3
bantime = 6h
```
@@ -332,7 +329,7 @@ Status for the jail: sshd
配置文件位置 `/etc/sysctl.conf`
```c
```conf
# mem
vm.swappiness = 10
@@ -341,6 +338,11 @@ net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_fastopen=3
net.ipv4.tcp_slow_start_after_idle=0
# zram 相关配置,配合下文 zram 使用
vm.watermark_boost_factor = 0
vm.watermark_scale_factor = 125
vm.page-cluster = 0
```
配置完之后保存并应用
@@ -349,7 +351,74 @@ net.ipv4.tcp_slow_start_after_idle=0
sudo sysctl -p
```
### 3.2 其他进阶配置
### 3.2 更多内存空间 - ZRAM
ZRAM 内存压缩对于个人服务器来说始终活跃的程序占用的内存只有比较小一部分启用 zram 可以将这部分内存压缩从而可以部署更多的服务
建议使用`zramtool`, 简单方便
```shell
sudo apt install zram-tools
```
修改`/etc/default/zramswap`, 末尾添加
```ini
ALGO=zstd
PERCENT=60
```
之后执行`sudo service zramswap reload`重载生效
可以使用 swapon 命令查看生效情况
```
~ » sudo swapon -show
NAME TYPE SIZE USED PRIO
/swap_space file 2G 32.1M -2
/dev/zram0 partition 489.9M 0B 100
```
这样一来会将机器物理内存的 50% 配置 zram, 使用 zstd 压缩算法一般压缩比能达到 3:1, 也就是说1G 的机器可以相当于有`0.5G+3*0.5G=2G`的内存
注意 Debian 新版本 swapon 等工具所在的目录 /usr/sbin 不在普通用户的 PATH 可能需要手动执行前缀使用 /usr/sbin/swapon
### 3.3 更多内存空间 - 关闭 kdump释放预留的内存空间
新服务器开起来之后你会发现无论是 htop 还是 free 等命令看到的总内存就是比你买服务器时页面上写的要小比如我开的两核 1G 的机器实际机器上看到的总内存只有 816M. 这是因为 linux 系统会默认开启 kdump预留了一部分内存不让我们使用
Kdump Linux 系统的一种内核崩溃转储机制它允许在系统发生内核崩溃例如内核 panic捕获内存的转储信息从而帮助事后分析故障原因默认的配置`2G-8G:256M,8G-16G:512M,16G-:768M`, 如果你买的是 2G 的机器上来就有 1/8 的空间用不了
但是我们个人日常使用的 linux 机器基本用不到这个功能不用预留这部分空间
操作方法有两种将预留内存改为 0 or 直接关闭 kdump 服务对于个人玩家小内存机器我建议直接关闭操作如下
```bash
# 备份grub配置文件
sudo cp /etc/default/grub /etc/default/grub.bak
# 编辑grub配置,删除 crashkernel=0M-2G:0M,2G-8G:192M 这样的部分
sudo nano /etc/default/grub
# 部分发行版镜像可能还有单独的kdump配置文件,直接删除
sudo rm /etc/default/grub.d/kdump-tools.cfg
# 更新grub配置
sudo update-grub
# 关闭并禁用Kdump服务
sudo systemctl disable kdump-tools
sudo systemctl stop kdump-tools
# 重启系统
sudo reboot
# 检查是否生效, 状态为 inactive(dead),即 kdump 服务已停止运行
sudo systemctl status kdump
# 检查 crash size 是否为0
cat /sys/kernel/kexec_crash_size
```
更多内容可以参见这篇文档[预留内存相关文档 - 阿里云](https://help.aliyun.com/zh/ecs/use-cases/view-and-change-the-size-of-reserved-memory-on-a-linux-instance#7d5ae6803amdp) 或者 [预留内存相关文档 - 腾讯云](https://cloud.tencent.com/document/product/213/115734)
### 3.3 其他进阶配置
一些其他的系统维护技巧与策略

View File

@@ -38,15 +38,15 @@
src="{{ "assets/prism.js" | absURL }}"></script>
<script defer onload="tocbot_init()"
onerror="fallbackJSloader('https://cdn.staticfile.org/tocbot/4.9.1/tocbot.min.js','tocbot_init')"
onerror="fallbackJSloader('https://s4.zstatic.net/ajax/libs/tocbot/4.9.1/tocbot.min.js','tocbot_init')"
src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js"></script>
<link rel="stylesheet"
onerror="fallbackCSSloader('https://cdn.staticfile.org/tocbot/4.9.1/tocbot.css')"
onerror="fallbackCSSloader('https://s4.zstatic.net/ajax/libs/tocbot/4.9.1/tocbot.css')"
href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.css">
<script defer onload="init_gitalk()"
onerror="fallbackJSloader('https://cdn.staticfile.org/gitalk/1.7.2/gitalk.min.js','init_gitalk')"
onerror="fallbackJSloader('https://s4.zstatic.net/ajax/libs/gitalk/1.7.2/gitalk.min.js','init_gitalk')"
src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<link rel="stylesheet"
onerror="fallbackCSSloader('https://cdn.staticfile.org/gitalk/1.7.2/gitalk.css')"
onerror="fallbackCSSloader('https://s4.zstatic.net/ajax/libs/gitalk/1.7.2/gitalk.css')"
href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.css">
<!-- no min css version fallback for gitalk css -->

View File

@@ -20,8 +20,8 @@ onerror="fallbackJSloader('https://cdn.staticaly.com/gh/panr/hugo-theme-hello-fr
src="{{ "assets/main.js" | absURL }}"></script>
<script async onload="panguSpaing()"
onerror="fallbackJSloader('https://cdn.staticfile.org/pangu/4.0.7/pangu.min.js','panguSpaing')"
onerror="fallbackJSloader('https://s4.zstatic.net/ajax/libs/pangu/4.0.7/pangu.min.js','panguSpaing')"
src="https://cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js"></script>
<script async onload="initQuickLink()"
onerror="fallbackJSloader('https://cdn.staticfile.org/quicklink/2.3.0/quicklink.umd.js','initQuickLink')"
onerror="fallbackJSloader('https://s4.zstatic.net/ajax/libs/quicklink/2.3.0/quicklink.umd.js','initQuickLink')"
src="https://cdn.jsdelivr.net/npm/quicklink@2/dist/quicklink.umd.js"></script>

View File

@@ -1,5 +1,3 @@
<!-- <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22>
<text y=%22.9em%22 font-size=%2290%22>👋</text></svg>"> -->
<link rel="icon" href="/favicon.png">
<link rel="apple-touch-icon" href="/favicon.png">