创建根CA证书并给特定网站签发（岛风go为例）
背景舰C在2025年大更新引入https后，用普通的VPN软件绕过地区限制不会受影响，因为VPN是直接做流量转发，不需要处理数据。而岛风Go等代理软件就没法像以前一样毫无阻碍地在中间转发了，如果不做任何设置，浏览器会把舰C网站标为证书无效，并阻止大多数的连接。因此，我们需要自行颁发并信任一些证书，让浏览器认为走代理的舰C网站是安全的。岛风Go基本原理具体这种带缓存魔改防猫的代理如何运作的并没有公开的说明，但用网络安全的基本知识也能猜个大概。在HTTP协议裸奔的年代，本地网页与服务器之间的通信会被代理软件“劫持”，即数据包发到本地后会首先进入代理软件，代理读取处理并修改信息后再把数据包发给浏览器。等浏览器想往服务器发包时，包首先也会发给代理，代理考虑是正常发给服务器还是做点修改。例如本地缓存和魔改，大概就是浏览器在向服务器请求图片资源时，代理直接返回自己存储的贴图。防猫，大概也是在发包后如果没收到服务器返回的OK，就把包扣着重新再发直到收到正确的回复。HTTPS和根证书想要知道为什么舰C换HTTPS后代理软件就挂了，需要先了解一点现代网站安全的基本知识。为了不让像登录密码这种敏感信息在互联网上裸奔，现代网站都使用了HTTPS协议，大致的工作原理是，服务器首先生成一套非对称加密（例如RSA）的公钥和私钥，浏览器访问服务器时，服务器把公钥明文发给浏览器，浏览器生成一个随机的对称加密（例如AES）的密钥，用服务器公钥加密后发给服务器，服务器用自己的私钥解密，之后的通信都使用这个对称加密的密钥来加密。在这个过程中，中间人攻击仍然很简单，代理软件只需要假装自己是客户端，跟服务器交换密钥后就能正常解密加密跟服务器的通信。然后再假装自己是服务器，跟浏览器交换密钥，便能跟HTTP一样实现所有功能了。为了堵住这个漏洞，HTTPS引入了CA证书系统。在互联网世界中有几个官方认证的CA机构，浏览器默认他们是可靠的，并且保存了他们的公钥。所有网站在生成自己的非对称私钥公钥时，都要找一个CA机构做认证。CA机构会将网站服务器的公钥先算hash，再用CA的私钥加密，作为这个网站的证书。当浏览器请求网页时，会同时得到明文的网站公钥，以及CA加密的证书。浏览器会使用系统里保存的CA公钥将证书解密，再与收到的网站公钥的hash做对比，如果不一样，则会认定为遭到了攻击，通常会拒绝后续的连接。这种情况下浏览器顶上域名栏左边会显示红色的警告。因此，代理软件假装自己是舰C服务器的企图就被识破了，因为它提供的服务器公钥和证书无法被浏览器已知的CA公钥验证。代理软件也不可能真的找一个CA机构来认证，毕竟认证时候你还得提供网站域名，不可能让人家机构认证你为dmm的服务器吧。所以我们只能假装自己是个CA机构，给自己颁发个证书，认证dmm和舰C服务器的域名，并将这个伪CA机构的信息添加进系统中，让浏览器认为你也是可靠的。岛风Go实际上提供了他们自己签发的全套证书，如果你不担心什么安全问题完全可以直接使用，但作为一名有点追求的计算机使用者，还是希望能自己控制整个伪造流程。自己签发CA证书以下为整套签发CA证书的流程，在Ubuntu下测试，Windows应该也大差不差。生成根CA私钥openssl genrsa -out myRootCA.key 4096生成自签名根证书openssl req -x509 -new -nodes -key myRootCA.key -sha256 -days 3650 -out myRootCA.crt生成网站私钥openssl genrsa -out ShimakazeGo.key 2048设置需要签名的网站以下设置是从岛风Go的证书文件里抄出来的，未来还可能会修改。保存为ShimakazeGo.cnf。[ req ] default_bits = 2048 prompt = no default_md = sha256 req_extensions = v3_req distinguished_name = dn [ dn ] C = CN ST = Shanghai O = ShimakazeGoCustom CN = ShimakazeGoCustom [ v3_req ] subjectAltName = @alt_names [ alt_names ] DNS.1 = *.cdn.dmmgames.com DNS.2 = *.cloudfront.net DNS.3 = *.touken-ranbu.jp DNS.4 = *.bilibiligame.net DNS.5 = *.yuyuyui.jp DNS.6 = *.shiropro-re.net DNS.7 = *.enza.fun DNS.8 = *.shinycolors.enza.fun DNS.9 = *.kamihimeproject.net DNS.10 = gskh-api-r-zh.prod.skh.johren.games DNS.11 = gskh-resource-r-zh.prod.skh.johren.games DNS.12 = prd-priconne-redive.akamaized.net DNS.13 = *.happyelements.co.jp DNS.14 = stars-assets.hekk.org DNS.15 = *.kanpani.jp DNS.16 = *.aimia.dmmgames.com DNS.17 = *.cdn.aimia.dmmgames.com DNS.18 = *.bungo.dmmgames.com DNS.19 = api-gameplayer.dmm.com DNS.20 = cdn2-gameplayer.games.dmm.com DNS.21 = fruful.jp DNS.22 = i-cf.alice.colopl.jp DNS.23 = game.mahjongsoul.com DNS.24 = dmc.mahjongsoul.com DNS.25 = game.maj-soul.com DNS.26 = *.magicami.jp DNS.27 = zu9j1t6ekm.user-space.cdn.idcfcloud.net DNS.28 = *.idolwars.jp DNS.29 = www.dmm.com DNS.30 = www.dmm.co.jp DNS.31 = p.dmm.com DNS.32 = p.dmm.co.jp DNS.33 = pics.dmm.com DNS.34 = pics.dmm.co.jp DNS.35 = games.dmm.com DNS.36 = games.dmm.co.jp DNS.37 = media.games.dmm.com DNS.38 = media.games.dmm.co.jp DNS.39 = files.gameplayer.games.dmm.com DNS.40 = osapi.dmm.com DNS.41 = osapi.dmm.co.jp DNS.42 = cdn-connect.mobage.jp DNS.43 = mist-train-girls.azureedge.net DNS.44 = *.mist-train-girls.com DNS.45 = mist-train-girls.azurefd.net DNS.46 = *.e-heroines.net DNS.47 = static-files-allb.pokelabo.jp DNS.48 = web-assets.otogi-frontier.com DNS.49 = otogi-rest.otogi-frontier.com DNS.50 = az-otogi-web-assets.azureedge.net DNS.51 = prd-storage-app-umamusume.akamaized.net DNS.52 = prd-storage-game-umamusume.akamaized.net DNS.53 = *.bokusen.net DNS.54 = millennium-war.net DNS.55 = all.millennium-war.net DNS.56 = assets-cn.millennium-war.net DNS.57 = ancl.jp DNS.58 = cdn-paripari-prod-002.azureedge.net DNS.59 = assets.game-monmusu-td.net DNS.60 = prd-game-a-granbluefantasy.akamaized.net DNS.61 = prd-game-a1-granbluefantasy.akamaized.net DNS.62 = prd-game-a2-granbluefantasy.akamaized.net DNS.63 = prd-game-a3-granbluefantasy.akamaized.net DNS.64 = prd-game-a4-granbluefantasy.akamaized.net DNS.65 = prd-game-a5-granbluefantasy.akamaized.net DNS.66 = pc-play.games.dmm.com DNS.67 = pc-play.games.dmm.co.jp DNS.68 = tracking.games.dmm.com DNS.69 = tracking.games.dmm.co.jp DNS.70 = d3mya90gbacu0m.cloudfront.net DNS.71 = dz87n5pasv7ep.cloudfront.net DNS.72 = cdn-r18.gc.dmmgames.com DNS.73 = cdn.gc.dmmgames.com DNS.74 = game-a.granbluefantasy.jp DNS.75 = game-a1.granbluefantasy.jp DNS.76 = game-a2.granbluefantasy.jp DNS.77 = game-a3.granbluefantasy.jp DNS.78 = game-a4.granbluefantasy.jp DNS.79 = game-a5.granbluefantasy.jp DNS.80 = *.kancolle-server.com生成csr文件openssl req -new -key ShimakazeGo.key -out ShimakazeGo.csr -config ShimakazeGo.cnf使用根CA签发网站证书，每年要更新openssl x509 -req -in ShimakazeGo.csr -CA myRootCA.crt -CAkey myRootCA.key -CAcreateserial -out ShimakazeGo.crt -days 825 -sha256 -extfile ShimakazeGo.cnf -extensions v3_req将证书转为pfx文件，这个是岛风Go认可的证书文件openssl pkcs12 -export \ -out ShimakazeGo.pfx \ -inkey ShimakazeGo.key \ -in ShimakazeGo.crt \ -certfile myRootCA.crt可以用如下命令查看pfx证书信息openssl pkcs12 -info -in ShimakazeGo.pfx重命名为customize_cert.pfx并放入ShimakazeGo目录将我们自己的CA证书导入浏览器的信任证书，Chrome在设置里找到隐私和安全，选择安全，管理证书，选择导入，然后将之前生成的myRootCA.crt文件加进来。最后重启岛风Go和浏览器，再打开舰C的页面，应该不再看到隐私警告了，同时点开域名左边的按钮，还能看到我们自己给dmm签发的证书。
前言部署一个网页本身并没有太大难度，租个服务器用默认密码ssh登入root装上Nginx把网页复制到/var/www里然后改一下Nginx的设置，再去Cloudflare把域名解析到你的IP地址，基本就搞定了。问题在于这么做过不了多久你就会发现服务器密码已经被穷举攻破，然后你就变成了肉鸡用于ddos。即使你手动改了个很复杂的密码，也会发现你命令行用起来非常卡，因为你服务器在后台拒绝大量的错误密码登录。因此，为了在这个险恶的互联网环境下生存下去，必须学会如何保护自己的服务器。服务器安全设置开服后第一件要做的事就是提升安全性。其实你部署完网页再做也行，但这一段每一项操作出错都有可能让你再也登录不了服务器，只能重装。为了少折腾，还是建议最开始就把这些危险操作都搞定。修改ssh端口并配置防火墙第一步我们把默认的ssh端口给改掉，并直接屏蔽22端口的访问。首先打开全局ssh配置文件sudo nano /etc/ssh/sshd_config，root账户可以不用sudo，找到Port 22这一行，把它改成任意与其他服务不冲突的端口，例如Port 1234，按Ctrl+X保存并退出。接着配置ufw防火墙，用sudo ufw allow 1234/tcp添加一个允许1234端口TCP连接的规则。为了防止输入错误导致再也连不上服务器，建议再临时添加一个sudo ufw allow 22/tcp，让当前的远程连接在激活防火墙后还能不断线。确保ssh端口和防火墙都配置正确后，先用sudo systemctl restart ssh重启ssh服务，这时可以再开一个控制台，用ssh -p 1234 root@your-server-ip-address连接服务器，如果能连上说明ssh配置是正确的。再在任意一个控制台里输入sudo ufw enable激活防火墙，如果新的连接没中断，说明防火墙配置也没问题。不放心可以再开个控制台测试一下。之后就可以把临时的22端口规则删掉了sudo ufw delete allow 22/tcp，这样那些对22端口的穷举爆破就会直接被拦住，不会影响服务器性能了。创建账户并赋予sudo权限直接使用root操作服务器是非常危险的行为，容易出现经典的rm -rf不慎删掉整个根目录的失误，因此，我们最好创建一个新账户，并赋予sudo的权限，这样可以避免一些操作失误干掉整个系统，多人使用服务器还能分别记录每个人各自的操作。我们用sudo adduser abc创建一个叫abc的用户，跟着提示输入密码等信息，然后将该用户添加进sudo用户组sudo usermod -aG sudo abc。接着开个新的控制台，用ssh -p 1234 abc@your-server-ip-address登入服务器，然后看看sudo命令是否能用，如果一切正常，可以去ssh设置里禁止直接用root登录，进一步提高安全性。找到/etc/ssh/sshd_config里的PermitRootLogin yes，改成PermitRootLogin no，用sudo systemctl restart ssh重启服务。以后所有root级操作都用新用户的sudo来提权运行，如果真的有什么需要用root用户的操作，可以用su root切换到root。设置仅允许密钥对登录即使改掉了ssh的端口号，如果攻击者真的想要爆破你的服务器，他们还可以直接扫描你的所有端口找到哪个用于ssh。禁用root登录可以有效防止陌生人找到正确的用户名穷举出你的密码，但是如果用上了社工手段，你的用户名很有可能能被猜出来，于是你的服务器还是有一定的危险。这里最安全的手段是只允许服务器使用密钥登录，这样除非你的私钥泄漏了，不然仅有你这台设备能登录。我们先在本地的控制台里，用ssh-keygen -t RSA -b 4096 -C 'comments'创建一个私钥公钥对，comments是备注，你可以改成自己当前电脑的信息。保存位置使用默认的就行，passphrase是解锁这个私钥的密码，设置一个你保证能记住的，最好把passphrase记在纸上。然后去刚才保存的位置，Windows通常在%USERPROFILE%/.ssh/，Ubuntu在~/.ssh/，里面能看到一个id_rsa文件和一个id_rsa.pub文件，没有后缀名的是你的私钥，不要让其他任何人知道。id_rsa.pub是公钥，把它发给别人，你用私钥加密的信息他们可以用公钥来解密。本地生成了私钥公钥对后，先照常用密码登录服务器，把你的公钥添加到服务器的信任列表中，用nano ~/.ssh/authorized_keys创建一个文件，把本地的id_rsa.pub里的内容完整地复制进去，Ctrl+X保存并退出。再打开/etc/ssh/sshd_config，把下面几个验证方式都改成no，只保留PubkeyAuthentication yes。PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no PubkeyAuthentication yes最后重启ssh服务，你也可以先不关闭当前的连接，再开一个控制台来测试连接。同样使用ssh -p 1234 abc@your-server-ip-address，系统会自动使用你个人文件夹下~/.ssh/id_rsa来与服务器配对，输入设置的passphrase，就能登录了。如果你有多台设备要登录到同一账号，最正确的操作是每台设备都生成自己的私钥公钥对，把新的公钥先发给第一台设备，再把新设备的公钥加到服务器。还有个简单的操作是直接把第一台设备的私钥复制到其他设备，服务器中只添加这一个公钥。虽然很不正规，也不符合私钥公钥本身的意义（可以看作是唯一的设备身份认证），但对于个人用服务器也足够安全了，同一个私钥多个设备备份还可以防止丢失。无论如何，强烈建议在安全的地方（例如移动硬盘或能信任的网盘）保存一份私钥，防止你电脑出现意外后再也登不上服务器。一些密钥相关操作创建一对RSA加密的公私钥对：ssh-keygen -t RSA -b 4096 -C 'comments'修改或添加私钥passphrase：ssh-keygen -p -f ~/.ssh/id_rsa修改或添加私钥comment：ssh-keygen -c -f ~/.ssh/id_rsa公钥comment直接用文本编辑器打开在末尾修改即可。将私钥添加进本地缓存，以后使用不需要输入passphrase：ssh-add ~/.ssh/id_rsa查看当前缓存了哪些私钥：ssh-add -l移除一个缓存的私钥：ssh-add -d ~/.ssh/id_rsa部署网页服务器加强了服务器安全后就可以来正式部署网页了。Nginx是非常适合个人网站的HTTP服务器，性能强，使用简单，网上还能找到大量的教程，我参考的是这个网站。安装Nginx首先用apt安装Nginx。sudo apt update sudo apt install nginx然后把HTTP和HTTPS的端口添加进防火墙：sudo ufw allow 'Nginx Full'。这时候可以在浏览器打开http://your-server-ip-address，如果能看到一个Welcome to nginx的页面那说明安装成功了。安装MySQL或任意数据库除非是非常小的纯静态网页，不然大多数网页都会使用一个数据库来存储网页里的数据。MySQL是曾经十分流行的一个免费开源数据库，其被甲骨文收购后，原作者团队基于MySQL分支开发了继续保持免费开源的MariaDB，二者用起来没什么区别。安装MySQL可以直接用apt：sudo apt install mysql-server，然后输入sudo mysql_secure_installation来执行一些安全措施。开始时会问你要不要使用强密码，可以根据你需求选择密码强度要求等级，不建议选STRONG，有点极端了，MEDIUM是比较合适的，要求有数字、大小写字母和特殊符号。接着会让你设置一个数据库root用户的密码，这里的root跟服务器的root不是同一个，注意不要混淆。后面的设置基本上一路确认就行了，会自动禁用一些不安全的设置，例如禁止远程登录数据库。流程跑完后可以用sudo mysql测试能否进入数据库管理，输入exit或者按Ctrl+D即可退出。可以注意到这里并没有要求验证任何密码，这是因为MySQL认为你都有sudo权限了，那肯定应该能随意处理数据库。但这也是个不太安全的行为，我们需要两个操作来让数据库更安全：要求root也要使用密码，以及创建仅能操作特定database的用户。MySQL设置root使用密码登录首先还是用sudo mysql进入数据库，注意后面的每个命令都要结尾加分号才会执行。可以输入SELECT user, host, plugin FROM mysql.user WHERE user = 'root';查看当前所有用户的登录验证方式，能看到root是auth_socket，即只要是服务器的root就可以直接登录。输入如下命令将root的登录方式改为仅密码：ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password; FLUSH PRIVILEGES;为了防止出问题，跟之前一样，可以开个新控制台，使用mysql -u root -p来使用密码登录root，注意以后登录数据库不再需要sudo提权。如果出现了问题，还可以在之前的连接中输入下面的命令来重设密码：# 仅当用之前设置的密码无法登录时 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码'; FLUSH PRIVILEGES;创建MySQL用户并给予权限部署网站时通常做法是为每个服务创建一个单独的数据库账号，仅给予每个账号访问对应数据库的权限。以数据库名data1，对应用户user1为例，先用root登入MySQL，然后进行如下操作：CREATE DATABASE data1; CREATE USER 'user1'@'localhost' IDENTIFIED WITH mysql_native_password BY '用户密码'; GRANT ALL ON data1.* TO 'user1'@'localhost'; FLUSH PRIVILEGES;这样就创建了一个新用户user1并给予了他完全控制data1的权限，可以用mysql -u user1 -p来登入。这里该用户的域是localhost，即本地用户。如果之后想要允许远程连接数据库，这里要把localhost改成一个百分号'%'。MySQL数据库备份这里顺便讲一下数据库备份。理论上使用MySQL的root用户可以执行所有操作，但是本着root能不用就不用的原则，我们可以再创建一个专门用于备份data1的用户。注意user1虽然能操作data1，但其并不能导出备份data1，因为缺少读取总数据的一些权限。这里我们单独为data1的备份创建一个data1_backup用户：CREATE USER 'data1_backup'@'localhost' IDENTIFIED WITH mysql_native_password BY '用户密码'; GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON `data1`.* TO 'data1_backup'@'localhost'; GRANT PROCESS, RELOAD, REPLICATION CLIENT ON *.* TO 'data1_backup'@'localhost'; FLUSH PRIVILEGES;以后每次需要备份时，输入mysqldump -u data1_backup -p data1 > backup_filename.sql即可。安装PHP根据你想要部署的网页框架安装所需版本的PHP：sudo apt install php-fpm php-mysql php-mbstring，mbstring库是用来正确处理非ASCII字符的。配置Nginx网页服务器必备的模块都安装好后我们就可以用Nginx来部署我们的网站了。首先我们在Nginx的网站存储位置创建一个项目文件夹sudo mkdir /var/www/你的域名，如果没有域名随便取个名字就行。注意/var/www/这个文件夹需要提权才能写入，但我们不能给网页服务器sudo权限，所以我们把这个项目文件夹所有权转给当前用户sudo chown -R $USER:$USER /var/www/你的域名。你可以在这个项目文件夹下先添加一个index.html文件，随便打几个字，用于之后的测试。接着我们创建一个我们网站的配置文件sudo nano /etc/nginx/sites-available/你的域名，里面先输入如下内容并保存：server { listen 80; server_name 你的域名 www.你的域名; root /var/www/你的域名; index index.html index.htm index.php; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; } location ~ /\.ht { deny all; } }其中的php版本根据你安装的来修改。这个最基本的配置文件设置了网站入口和PHP解析器，但仅支持HTTP连接，如今随着浏览器（特别是Google Chrome）安全标准的提高，一个网站如果不使用HTTPS协议加密，很有可能会被直接禁止访问。不过我们先把后面的网站服务器基本设置搞定再折腾SSL证书。下一步是把我们网站的配置文件作为当前使用的配置文件sudo ln -s /etc/nginx/sites-available/你的域名 /etc/nginx/sites-enabled/，同时把默认的删除sudo unlink /etc/nginx/sites-enabled/default。然后让Nginx检查你的配置文件是否合法sudo nginx -t，并重新加载sudo systemctl reload nginx。现在再访问http://your-server-ip-address，应该可以看到你在index.html里随机打的字了。为了测试PHP是否正确安装，你还可以在项目文件夹中创建一个info.php文件，输入：<?php phpinfo();然后浏览器打开http://your-server-ip-address/info.php查看是否显示了调试信息。域名与SSL设置为了使用HTTPS协议，我们需要给自己的网站配置一个SSL证书。参考如下文章，我们用免费的Certbot来给我们的网站签发一个证书。前提条件是你已购买一个域名，并用Cloudflare或相似DNS服务商把该域名指向了你的服务器IP地址，要同时设置xxxx.com和www.xxxx.com。先安装需要的程序sudo apt install certbot python3-certbot-nginx，然后输入sudo certbot --nginx -d 你的域名 -d www.你的域名来签发证书，第一次使用会要求你填写邮箱地址。然后Certbot会自动在你网站的Nginx配置文件里添加一些条目。可以打开确认一下是否主配置里的监听端口改成了listen 443;，还增加了一些包含certbot注释的行，最后还把80端口导向了404错误。现在你就可以用https://your-server-ip-address来访问自己的网站了，能看到浏览器非常开心地给了你安全的标志。Certbot签发的SSL证书有效期为90天，到期会自动更新，一般不再需要去关心了。最后的细节根据网站框架的不同还有一些小细节需要处理一下，如果你像我一样使用GitHub来同步代码，同时网站有上传附件的功能，需要在Nginx的网站配置文件里设置一个最大附件体积，还要禁止访客访问.git文件夹，因为其中很可能存储了例如你的姓名和邮箱等信息，最好不要让攻击者知道。server { root /var/www/你的域名; # 一些其他配置 client_max_body_size 100M; location ~/\.git { deny all; } # 更多配置 }（可选）利用Docker部署
前言使用Ubuntu时，很多软件并不包含在apt包管理工具中，或者apt提供的版本太老，因此我们时常需要下载已编译好的软件。为了避免依赖问题，这些软件有时会打包成AppImage，下载下来后直接双击打开就能运行，任务栏可以看到正确的软件图标。但如果要把这个软件像apt安装的软件一样添加到应用程序列表里，还需要一些额外操作获取软件图标。具体步骤以Mesh Lab这个程序为例，从官网下载的是一个.AppImage文件，可以看到这个文件的图标是默认的小齿轮。但给这个文件赋予执行权限chmod 755 MeshLab.AppImage并双击执行后，能看到任务栏里有正确的程序图标。我们首先从程序包中提取图标。在命令行中输入./MeshLab.AppImage --appimage-extract可以提取出应用的所有文件，其中可能有个xxx.png的图标文件，同时可能还有个文件夹叫usr，打开后还有share/icons等文件夹，继续深入文件夹可以看到包含各个分辨率的图标的文件夹，每个分辨率下的文件名应该是相同的，例如我这里是usr/share/icons/hicolor/512x512/apps/meshlab.png，记住这个名字。接着，我们要确认这个程序是所有人都可使用，还是仅当前用户需要。如果要让所有用户使用，通常我们会把AppImage放在根目录的/opt/文件夹下，然后把各分辨率图标复制到/usr/share/icons/里。如果仅有一个图标，可以考虑根据它的分辨率把它丢到对应的icons/hicolor/分辨率/apps/文件夹下，也可以把这张图放在/opt里，之后使用绝对路径。如果仅当前用户使用，则把这个AppImage放在自己的home目录下，放哪都无所谓，我是创建了一个~/Applications/文件夹专门存放所有的预编译应用。同样我们要把应用图标放到正确的位置，这里是放在自己home目录的~/.local/share/icons/。我们还需要获取程序运行时窗口的名字。直接双击AppImage运行这个程序，打开一个命令行并输入xprop | grep WM_CLASS，鼠标会变成一个十字，在程序窗口中点一下，命令行中会显示窗口的名字，例如Mesh Lab这里是WM_CLASS(STRING) = "AppRun.wrapped", "MeshLab_64bit_fp"，记下后一个名字，这里是MeshLab_64bit_fp。准备工作都做好后，创建一个文件起名叫meshlab.desktop，文件名叫什么无所谓，自己能认得就行。如果想要对所有用户生效，把这个文件放在/usr/share/applications/里，如果只需要对当前用户生效则放在~/.local/share/applications/。用记事本打开，写入如下内容：[Desktop Entry] Type=Application Name=MeshLab Exec=/opt/MeshLab.AppImage %F Icon=meshlab Terminal=false StartupWMClass=MeshLab_64bit_fp这些条目中，Type、Name、Exec是必须要有的，Type一般就是Application，Name是在应用菜单和任务栏里会看到的名字，Exec是程序运行的路径和参数，这里的%F指传递文件名参数，可能类似于把文件拖动到图标上这个操作，具体要填什么参数取决于应用的需求。Icon和StartupWMClass也是非常推荐填写的字段。如果之前把各分辨率的图标复制到了.../share/icons里，Icon字段填写图标的文件名，不含后缀。如果使用单一图标，Icon填写图标的绝对路径，例如/opt/meshlab.png。StartupWMClass不填写时默认为等于Name字段，如果该字段跟程序实际打开的窗口名称不匹配，打开程序将会在任务栏创建一个新的图标，而不是在原有图标位置打开，所以这里填写我们之前用xprop | grep WM_CLASS获取的窗口名称。还有其他一些字段会提供一些额外信息，Terminal告诉系统打开这个程序时是否要打开终端，如果不填默认为false，Comment是应用简介， Categories可以让程序出现在某些应用分类下，MimeType说明了支持的文件类型，在打开对应文件时系统会显示这个程序作为可选项。如果是要开发一个正规的程序，这个字段都是很有用的应用信息，但我们就是创建一个图标而已，填不填都无所谓。最后我们还需要刷新一下图标缓存和列表，用户级别的刷新是update-desktop-database ~/.local/share/applications和gtk-update-icon-cache ~/.local/share/icons/hicolor，系统级别的是sudo update-desktop-database /usr/share/applications和sudo gtk-update-icon-cache /usr/share/icons/hicolor。参考信息感谢ChatGPT老师提供了大多数信息。
Ubuntu 22.04安装轻量级Win10虚拟机来实现OneDrive同步文件夹
背景其实对于绝大部分人来说，Linux系统想要使用OneDrive同步，直接装一个第三方客户端就能用了，比如我之前用的这个，虽然基本都不支持自动同步，但每次有什么更改手动输命令同步一下也够用了。然而某一天，大概是学校新换了个IT管理员，ban掉了所有没有微软官方认证的第三方客户端，纯纯的脑瘫。但没办法人家就是头头，只能认栽，找别的办法来同步Linux上的OneDrive文件夹。最终决定是装一个轻量级的Win10虚拟机，利用RDP远程桌面协议来操作，然后把Windows里的OneDrive文件夹共享，并挂载在Ubuntu的文件系统里。有意思的是这顺便还达成了自动同步，坏处就是CPU和内存占用高了一点，但影响并不是很大。操作流程配置虚拟机这里使用了KVM虚拟机平台实现一个轻量级的虚拟机，可以再配合WinApps把一些Windows软件直接做成一个Ubuntu里的小程序。配置流程基本完全参考了这篇教程。安装KVM：sudo apt-get install virt-manager。从微软官网下载Win10的ISO镜像，必须下载Pro版本的以使用远程桌面。太长了懒得一步步写了，直接跟着这个流程配置虚拟机，我只考虑使用OneDrive，所以分配的资源比较少，CPU两个核，最大4G内存，64G硬盘。继续跟着下一个流程安装Win10，注意在安装virt-win-gt-64.exe后还要安装一下同一文件夹下的virtio-win-guest-tools.exe来共享剪贴板，然后再安装那个Spice Guest Tools。可以把分辨率调低一些节省更多资源，比如800x600。如果想要使用WinApps，可以跟着这个步骤来安装配置。共享Windows虚拟机的文件夹先在网络设置里把当前网络设置为专用网络，并在网络和共享中心里打开专用网络下的网络发现和文件共享。右键OneDrive文件夹 -> 属性 -> 共享，选择高级共享，勾选共享此文件夹，下面的权限里删除所有人，添加自己的用户名，勾选完全控制，一路确认。Windows里打开Powershell，输入ipconfig获得虚拟机的IP地址。Ubuntu里创建一个挂载点文件夹，比如sudo mkdir /mnt/OneDrive。Ubuntu里用Samba挂载OneDrive文件夹sudo mount -t cifs '//windows_ip_address/OneDrive' /mnt/OneDrive -o username=username,password=password,dir_mode=0777,file_mode=0777，windows_ip_address、OneDrive文件夹名字、username、password改成你的。如果想要达成Ubuntu开机自动挂载OneDrive，需要虚拟机的Win10不设密码，开机能自动登入系统。但是Windows默认不允许无密码用户共享文件夹，参考这个网站，在Windows里win+r运行gpedit.msc组策略编辑器，Windows设置 -> 安全设置 -> 本地策略 -> 安全选项 -> 账户：使用空密码的本地账户只允许进行控制台登录，选择已禁用。英语的选项为Windows Settings -> Security Settings -> Local Policies -> Security Options -> Account: Limit local account use of blank passwords to console logon only，设置为disabled。然后刚刚的挂载命令的password=留空。在Ubuntu的Startup Application中添加一条bash -c "sleep 10 && echo sudo_password | sudo -S -k mount -t cifs '//windows_ip_address/OneDrive' /mnt/OneDrive -o username=username,password=,dir_mode=0777,file_mode=0777"，sudo_password改成自己的sudo密码。sleep 10是为了等待Windows开机进系统。共享Linux主机的文件夹虚拟机的内存设置里要勾选Enable shared Memory。选择Add Hardware，选择Filesystem，Driver用virtiofs，Source path选择Ubuntu主机里要共享的文件夹位置，Target path自己起个名字，比如VMShare。下载并安装Windows File System Proxy。在Windows的服务里找到VirtIO-FS Service，启动并设置为自动启动。在我的电脑下应该能看到出现了一个叫VMShare的目录。但是这个目录不能用于OneDrive的同步目录，不然都不需要单独给虚拟机划分空间了。参考资料https://github.com/Fmstrat/winappshttps://ivpsr.com/774.html
背景之前一直用Teamviewer来连接家里或者学校的电脑（主要是舰娘插件的统计数据不能网络同步，还是固定挂在一台电脑上比较方便），前两天Teamviewer说检测到我在给别人提供支持，ban了我个人license，必须要付费才能继续用。这么一个破远程桌面我肯定是不愿意一个月付十几二十欧的，果断卸载。以前只用Windows的时候一直在用Chrome远程桌面，连接没有Teamviewer流畅，对多屏幕的支持不太好，也没有文件传输这种功能。但是，它完全免费！！之前在Ubuntu没有用这个的原因是一直配置不好，连接打开只能看到黑屏。这次参考网上的信息，成功配置好了。安装配置第一步肯定是安装Google Chrome浏览器，然后安装Chrome Remote Desktop插件。打开插件后可以看到有个共享这台电脑的选项，会下载一个安装包，使用sudo dpkg -i chrome-remote-desktop_current_amd64.deb安装，如果报告缺少依赖，使用sudo apt install -f来安装。如果这个时候刷新Chrome Remote Desktop插件，会说无法启动远程桌面，必须手动mkdir ~/.config/chrome-remote-desktop给它创建一个存储配置的文件夹。在插件里点击启动，设置一个PIN，可能会要求输入sudo的密码。这时候我们的电脑出现在了可连接的列表里，然而连接它会显示一个完全的黑屏，而且我们电脑上被创建了一个新的桌面，但我需要的是连上一直在用的桌面。手动修改远程桌面的代码，先停止远程桌面的服务/opt/google/chrome-remote-desktop/chrome-remote-desktop --stop，然后用喜欢的文本编辑器打开代码源文件sudo gedit /opt/google/chrome-remote-desktop/chrome-remote-desktop，不放心可以先复制到别的地方备份一下。找到DEFAULT_SIZES，我这在77行，修改为自己显示器的分辨率，例如DEFAULT_SIZES = "1920x1200"。命令行输入echo $DISPLAY确认当前显示器编号，我这显示的是:1。找到代码中的FIRST_X_DISPLAY_NUMBER，我这在112行，改为自己的显示器编号，例如FIRST_X_DISPLAY_NUMBER = 1。注释掉1385-1386行的寻找更多显示器的代码。# while os.path.exists(X_LOCK_FILE_TEMPLATE % display): # display += 1把741行附近的launch_session函数整个改写成下面这样，让远程桌面使用当前桌面而不是创建一个新的。Reddit原文中调用了_setup_pulseaudio()函数，但我没找到这个函数的定义，有可能是新版本不用了，就先注释掉了。因为我不开声音，所以还不知道有什么影响。def launch_session(self, server_args, backoff_time): """Launches process required for session and records the backoff time for inhibitors so that process restarts are not attempted again until that time has passed.""" logging.info("Setting up and launching session") self._init_child_env() # self._setup_pulseaudio() self._setup_gnubby() # self._launch_server(server_args) # if not self._launch_pre_session(): # # If there was no pre-session script, launch the session immediately. # self.launch_desktop_session() # self.server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, # backoff_time) # self.session_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, # backoff_time) display = self.get_unused_display_number() self.child_env["DISPLAY"] = ":%d" % display保存文件，用/opt/google/chrome-remote-desktop/chrome-remote-desktop --start重新启动服务，并祈祷能用了。设置开机自动启动由于chrome remote desktop的服务是用户级别的，因此并不能随着开机自动启动，每次开机只有登录进去之后才能自己手动开启，有点麻烦。可以自己在Ubuntu桌面提供的Startup Application 中加入一个条目，Command设置为bash -c "sleep 5 && echo sudo_password | sudo -S -k systemctl start chrome-remote-desktop@username"，意思是在用户登录后延迟五秒后开启chrome远程桌面服务，把sudo_password和username替换为自己的。需要注意的是这里会把自己的用户密码明文写在命令里，介意的慎用。参考资料https://www.reddit.com/r/Ubuntu/comments/wrp4dr/ubuntu_2204_and_chrome_remote_desktop_trouble/
背景在深度学习的工作中有时候会用到C++写的Cuda函数来提高运行效率，例如这个Point-Bert，需要自行编译Chamfer Distance和Earth Mover's Distance (EMD)模块。但是在Conda环境里，跟着PyTorch一起安装的pytorch-cuda或cudatoolkit只有基本的Runtime，并不能用来编译Cuda代码。如果系统环境内安装了跟Conda环境里一样的Cuda版本，那可能能顺利编译。但通常我们用Conda环境就是为了能在安装不同PyTorch版本的时候不用折腾系统的Cuda，所以基本都会在编译时遇到系统Cuda和PyTorch Cuda版本不一样的错误。前段时间NVIDIA推出了官方的Conda环境Cuda安装包，这里参考这个官方教程来配置我们的Conda环境。具体操作这里直接记录下个人对Point-BERT的环境配置步骤，其他工作应该也大同小异。确定安装哪个版本的PyTorch，去官网查看需要哪个Cuda版本，安装Cuda。安装所有Conda能装的包，除了PyTorch。pip安装PyTorch，注意选择正确的Cuda版本。pip安装其他conda没有的包。注意opencv的pip版本可能会有些Qt的不兼容问题，可能装Conda版本更好。设置C++编译器的Linker路径到Conda环境。编译Cuda代码并安装到Conda环境。每次开新的命令行运行代码前都要设置C++的Linker路径。mamba create -n pointbert python=3.7 # mamba的速度比conda快多了 conda activate pointbert mamba install cuda -c nvidia/label/cuda-11.7.1 # 改为需要的cuda版本 mamba install easydict h5py matplotlib numpy opencv pyyaml scipy tensorboardX tqdm transforms3d termcolor scikit-learn ninja gcc=11.4 gxx_linux-64 libgcc notebook flake8 ipywidgets urllib3 requests charset-normalizer # gcc的版本需要根据之后编译时的报错来更改 pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu117 # 用pip来装PyTorch，不用装PyTorch提供的cuda包 pip install open3d==0.9 timm==0.4.5 argparse # 安装其他pip包 export LD_LIBRARY_PATH=/path/to/conda/envs/pointbert/lib # 手动设置C++ Linker路径，之后运行Python代码前也要设置一下 cd extensions/chamfer_dist python setup.py install # 会装到/path/to/conda/envs/pointbert/lib/python3.7/site-packages cd ../emd python setup.py install cd ../.. pip install "git+https://github.com/erikwijmans/Pointnet2_PyTorch.git#egg=pointnet2_ops&subdirectory=pointnet2_ops_lib" pip install --upgrade "https://github.com/unlimblue/KNN_CUDA/releases/download/0.2/KNN_CUDA-0.2-py3-none-any.whl"
前言ROS是机器人控制领域绕不开的一个框架，用起来也确实很方便，但这框架用官方安装教程只能装在系统的Python环境里。这样装写点最基础的控制没问题，但通常大家不会在系统Python环境里装太多包，特别是PyTorch这类神经网络框架，可能不同模型要装不同的版本。通常大家会用Conda这种包管理软件来创建一个新的环境专门用于某个项目，然而在Conda环境里是没法使用ROS的，所以对于涉及机器人学习的项目，我们需要把ROS的包给装进Conda环境里。最近发现有个叫RoboStack的项目可以实现这个Conda环境，还可以安装非官方支持的ROS版本（比如在20.04里装Humble），但同时也会带来一堆麻烦的依赖问题，特别是C++项目的编译。这里记录一下如何安装以及如何丑陋地解决Azure Kinect相机驱动没法编译的问题。安装前准备Mamba是一个基于Conda但比Conda快得多的包安装软件。如果还没装Conda，可以选择直接去官网下载并安装Mambaforge，会自动安装Conda和Mamba以及设置一些channel。如果已经装了Conda，可以在base环境下设置并安装Mamba。安装Mamba conda install mamba -c conda-forge，如果base环境里包有点多（例如装了Anaconda而不是Miniconda）或者好久没更新，可能这一步要花几十分钟时间解析依赖，这没啥办法只能硬等。然后可以把conda-forge源给添加到conda的设置里，这样就不用每次都-c conda-forge了。先把环境里的包都换源到conda-forge的mamba update --all -c conda-forge，然后执行conda config --add channels conda-forge和conda config --set channel_priority strict。这步可以不做，或者只在特定的环境里加上--env来只设置当前环境的默认源。安装ROS和PyTorch如果没有添加conda-forge到默认源，以下每一步都要加上-c conda-forge。首先创建一个新环境：mamba create -n ros_torch conda activate ros_torch # 如果直接装了Mambaforge，这里conda改为mambaROS 1和ROS 2选一个装，如果不想打-c robostack-staging，也可以把这个源加进环境设置里conda config --add channels robostack-staging。ROS 1：mamba install ros-noetic-desktop -c robostack-staging mamba install compilers cmake pkg-config make ninja catkin_tools -c robostack-stagingROS 2：mamba install ros-humble-dekstop -c robostack-staging mamba install compilers cmake pkg-config make ninja colcon-common-extensions -c robostack-staging跟apt安装的ROS差不多，有很多额外的ROS库可以安装，只需要mamba install ros-<distro>-<name> -c robostack-staging，可以去RoboStack官网看他们支持哪些库，目前还没碰到要用的库他们没收录的。安装好后可以先测试一下ROS能不能用，打开一个新的命令行，激活ros_torch环境后就可以运行内置的demo了，不要source系统的ROS安装目录。注意Conda环境的ROS不能跟系统环境的共用同一个workspace，需要为Conda的ROS创建一个新的workspace并在Conda环境下build。然后就可以安装PyTorch等神经网络框架了，需要注意的是如果没添加conda-forge源，必须每个命令都手打-c conda-forge，即使PyTorch的教程没有写。当前PyTorch安装命令为：conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia。还可以再顺手安装一些常用的库：mamba install tqdm matplotlib numpy pandas seaborn Pillow scipy pyyaml easydict gdown black flake8 notebook。使用Azure Kinect ROS DriverROS连接Azure Kinect相机需要安装基础驱动和ROS驱动。对于Ubuntu18.04系统加上系统环境的ROS 1，可以直接跟着官方教程安装Azure Kinect SDK，再在ROS的workspace/src里git clone https://github.com/microsoft/Azure_Kinect_ROS_Driver.git，把CMakeLists.txt的k4a和k4abt版本改成对应的SDK版本，如果build还是报版本号错误，需要去修改k4a安装的cmake，应该在/usr/lib/x86_64-linux-gnu/cmake/k4a。如果是Ubuntu20.04，则需要自己从微软的k4a-dev源以及k4a-tools源下载deb包并自行dkpg -i xxx.deb安装。在Conda环境的ROS里用Azure Kinect就有点麻烦了，因为Conda提供的build系列工具似乎不愿意去系统的/usr/lib/x86_64-linux-gnu里找SDK的依赖……还好Azure Kinect ROS驱动提供了一种直接把SDK依赖塞进ROS包的Azure_Kinect_ROS_Driver/ext/sdk的选项。同样，先去微软的k4a-dev源以及k4a-tools源下载libk4a1.4、libk4a1.4-dev和k4a-tools_1.4.1的deb包，不要安装而是直接解压，再解压里面的data压缩包，可以得到一个usr文件夹。k4a-tools的usr/bin直接丢进ext/sdk/bin；libk4a1.4里，usr/share直接丢进ext/sdk/share，usr/lib/x86_64-linux-gnu里的所有文件包括链接放进ext/sdk/lib；libk4a1.4-dev里，usr/include直接丢进ext/sdk/include，usr/lib/x86_64-linux-gnu里的cmake放进ext/sdk/lib。同时，把cmake里的k4a/k4aTargets.cmake和k4arecord/k4arecordTargets.cmake的第58行都注释掉。然后应该就可以在Conda ROS环境中构建Azure Kinect的ROS驱动了。使用Azure Kinect的ROS驱动前，需要安装几个ROS依赖：mamba install ros-noetic-image-geometry ros-noetic-camera-info-manager ros-noetic-rgbd-launch -c robostack-staging。
背景Ubuntu20.04的系统桌面里自带的命令行Terminal和文件管理软件Nautilus都不够好用，Terminal不能分栏，Nautilus查看复制文件夹路径很麻烦，打开根目录和挂载的分区也非常麻烦，不明白Ubuntu怎么会默认使用这么烂的基础软件。所以每次装上系统第一件事就是把这两个破烂换掉。本流程同样适用于Ubuntu22.04。步骤安装Terminator首先安装Terminator sudo apt-get install terminator，理论上现在 ctrl+alt+t会自动打开Terminator了，如果没有，可以自行设置一下 sudo update-alternatives --config x-terminal-emulator，然后选择Terminator的选项。右键菜单添加Terminator使用Nemo的话这一步就很简单了，只需要在安装Nemo后设置 gsettings set org.cinnamon.desktop.default-applications.terminal exec terminator，右键菜单里的Open in Terminal就会自动打开Terminator。如果还想继续使用Ubuntu默认的Nautilus文件管理，首先用 sudo apt-get remove nautilus-extension-gnome-terminal把自带的Open in Terminal去掉。然后安装一个管理插件 sudo apt-get install filemanager-actions，打开设置 fma-config-tool。添加一个新action，如下面两张图设置。然后再把Edit->Preferences里的创建一个根菜单给取消掉。最后保存一下，用 nautilus -q重启一下，就能看到右键菜单多了个Open in Terminator。安装Nemo并设为默认首先安装Nemo sudo apt-get install nemo然后设置Nemo为默认文件管理和默认桌面：xdg-mime default nemo.desktop inode/directory application/x-gnome-saved-searchgsettings set org.gnome.desktop.background show-desktop-icons falsegsettings set org.nemo.desktop show-desktop-icons true到这一步对我来说就够用了，有教程说要再安装一个管理工具 sudo apt-get install gnome-tweak-tool然后关掉Desktop Icon，然后把nemo-desktop加入开机启动，因为我从不使用桌面，所以并没有做这一步。然后Ubuntu有个非常垃圾的一点，就是各种软件的保存打开界面调用的对话框没法换掉，依然是Nautilus风格的，非常难用，大概只能忍着了。在Nemo中添加自定义右键动作在右键菜单中添加一些功能可以让文件管理器更好用，Nemo中的动作可以自行在~/.local/share/nemo/actions中添加，动作的后缀名必须为*.nemo_action。用VSCode打开创建一个vscode.nemo_action：[Nemo Action] Active=true Name=Open in Code Comment=Opens current folder on vscode Exec=code %P Icon-Name=com.visualstudio.code Selection=none Extensions=any Quote=double Dependencies=code这里会有个问题，右键运行的命令不会经过bash，所以.bashrc里定义的环境变量无法加载，对于Python插件似乎没啥问题，但Latex Workshop会找不到texlive。我的解决办法是把之前写在.bashrc里的texlive环境PATH="$PATH:/usr/local/texlive/2023/bin/x86_64-linux"移到.profile里，这个是无论如何都会加载的环境配置，注意要注销重新登录才能刷新环境配置。批量重命名Linux Mint自带的Nemo似乎内置了Bulky批量重命名的功能，但Ubuntu没有，得自己装了配置一下。首先下载Bulky源码并编译安装，cd ~/Downloads mkdir bulky_source cd bulky_source git clone https://github.com/linuxmint/bulky.git cd bulky dpkg-buildpackage -uc -us sudo dpkg -i ../bulky*.deb sudo apt -f install可以看到开始菜单里多了个File Renamer的图标。然后在~/.local/share/nemo/actions/里添加一个bulky.nemo_action：[Nemo Action] Active=true Name=Bulky Rename Comment=Rename multiple files Exec=bulky %F Icon-Name=folder Selection=m Extensions=any Quote=double Dependencies=bulky然后就可以在选中多个文件的时候右键打开Bulky来批量重命名了。引用来源本文章基本参考了以下几个网站：https://blog.csdn.net/weixin_43640082/article/details/110678921https://blog.csdn.net/zhanghm1995/article/details/89419109https://itsfoss.com/install-nemo-file-manager-ubuntu/https://askubuntu.com/questions/1066752/how-to-set-nemo-as-the-default-file-manager-in-ubuntu
简介由于之前常用的安装FFmpeg的PPA变成了收费的，以后只能自己从源码编译FFmpeg和MPV，这里记录一下操作流程。安装FFmpeg根据这里的官方的教程可以比较简单地完成FFmpeg的编译，但通常没必要装到用户的home目录，所以要更改一些选项。注意MPV最新版可能需求FFmpeg-6.0以上，所以源码直接下最新的就好。安装依赖先装上一些apt能装的依赖。统计并不全，如果编译过程提示找不到xxx，那就先试试sudo apt-get install libxxx-dev。有的包可能会出现apt显示已安装，但编译器还是会说找不到.so文件，可能是因为之前卸载包时候没有卸干净，这时候就要sudo apt-get install libxxx-dev --reinstall来重装一下这些包。下面这些包从Ubuntu 20.04开始就有提供。sudo apt-get update sudo apt-get install \ autoconf \ automake \ build-essential \ cmake \ git \ libfreetype-dev \ libgnutls28-dev \ libmp3lame-dev \ libsdl2-dev \ libtool \ libva-dev \ libvdpau-dev \ libvorbis-dev \ libxcb1-dev \ libxcb-shm0-dev \ libxcb-xfixes0-dev \ libunistring-dev \ libaom-dev \ libx264-dev \ libx265-dev \ libnuma-dev \ libvpx-dev \ libfdk-aac-dev \ libopus-dev \ libjpeg-dev \ pkg-config \ texinfo \ wget \ yasm \ nasm \ zlib1g-dev其中，libx264用于H.264编码，libx265和libnuma用于H.265编码，libvpx用于VP9编码，libfdk-aac用于AAC音频编码，libopus用于Opus音频编码。用于编译的meson和ninja在Ubuntu 24.04可以直接用apt安装。sudo apt-get install ninja-build meson老版本的Ubuntu可能apt仓库里没有新版的meson和ninja，可以用pip可以安装最新的版本，注意要sudo（新的系统自带Python甚至不允许你直接用pip安装软件，其实是个很合理的设计）。sudo apt-get install python3-pip sudo pip3 install meson ninja用于AV1格式编解码的libsvtav1, libdav1d和用于字幕的libass在Ubuntu 24.04的官方仓库都有比较新的版本了，可以直接安装。sudo apt-get install libsvtav1-dev libdav1d-dev libass-devUbuntu22.04官方的apt提供了libsvtav1-dev，libdav1d-dev，libass-dev，版本都比较老。其中libsvtav1-dev装的是0.9.0版本，ffmpeg不认，必须手动编译。另外两个似乎能用，可以考虑不折腾。更老的Ubuntu应该是都要手动编译了。[collapse status="false" title="源码编译libsvtav1, libdav1d, libass"]源码编译libsvtav1直接从master编译应该也无所谓，但checkout到release分支感觉安心一点。FFmpeg只用到了Encoder，所以设置BUILD_DEC为OFF。git clone https://gitlab.com/AOMediaCodec/SVT-AV1.git cd SVT-AV1 git checkout v1.7.0 mkdir build && cd build cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_DEC=OFF -DBUILD_SHARED_LIBS=OFF .. make sudo make install源码编译libdav1ddav1d是个比libaom速度快得多的AV1解码器，可能有的apt-get的repo提供libdav1d-dev，但我这的没有，所以也要从源码编译。同样的，切到最新的release分支。git clone https://code.videolan.org/videolan/dav1d.git cd dav1d git checkout 1.2.0 mkdir build && cd build meson setup --default-library=static .. ninja sudo ninja install源码编译libassUbuntu20.04的apt-get是有libass-dev的，但版本太老了，所以还是自己来编译吧。从这里下载最新release的源码（source code zip），解压得到libass-x.x.x，比如0.17.1。先要装一些依赖。如果libfontconfig-dev安装了还是提示缺失，需要sudo apt-get upgrade libfontconfig-dev --reinstallsudo apt-get update sudo apt-get install \ libfreetype6-dev \ libfontconfig-dev \ libfribidi-dev \ libharfbuzz-dev然后配置并安装libass。cd libass-0.17.1 ./autogen.sh ./configure make sudo make install[/collapse]源码编译libvmaflibvmaf用于计算网飞的VMAF指标，所有的Ubuntu版本都需要手动编译。从这里下载最新的release源码并解压，会得到一个vmaf-x.x.x的文件夹，比如vmaf-3.0.0。cd vmaf-3.0.0/libvmaf meson build --buildtype release ninja -vC build ninja -vC build test sudo ninja -vC build install源码编译FFmpeg一套操作下来终于可以开始编译FFmpeg了。从这里下载FFmpeg的源码，解压得到文件夹ffmpeg-x.x.x。cd ffmpeg-x.x.x ./configure \ --extra-libs="-lpthread -lm" \ --ld="g++" \ --enable-gpl \ --enable-gnutls \ --enable-libaom \ --enable-libass \ --enable-libfdk-aac \ --enable-libfreetype \ --enable-libmp3lame \ --enable-libopus \ --enable-libsvtav1 \ --enable-libdav1d \ --enable-libvorbis \ --enable-libvpx \ --enable-libx264 \ --enable-libx265 \ --enable-pic \ --enable-nonfree make sudo make install这样就把FFmpeg，FFplay，FFprobe装到了/usr/local/bin。可以ffmpeg试试能不能用。安装MPVMPV是个跨平台的视频播放器，可以按官方的安装教程，一键把所有该装的全装了，但我们已经自己装了FFmpeg和libass，没有重装一次的必要，所以我们自己只编译安装MPV。安装完后参考vcb的教程去配置播放器。安装依赖参考了mpv-build/debian/control，不清楚哪些是已经装好的，总之就都装一下吧。sudo apt-get update sudo apt-get install \ ladspa-sdk \ libasound2-dev \ libarchive-dev \ libbluray-dev \ libbs2b-dev \ libcaca-dev \ libcdio-paranoia-dev \ libdrm-dev \ libdvdnav-dev \ libegl1-mesa-dev \ libepoxy-dev \ libgl1-mesa-dev \ libgbm-dev \ libgme-dev \ libgsm1-dev \ libjack-jackd2-dev \ libbrotli-dev \ liblcms2-dev \ liblircclient-dev \ liblua5.2-dev \ libmodplug-dev \ libopenal-dev \ libopencore-amrnb-dev \ libopencore-amrwb-dev \ libpulse-dev \ librtmp-dev \ librubberband-dev \ libssh-dev \ libsoxr-dev \ libspeex-dev \ libtool \ libuchardet-dev \ libvdpau-dev \ libvorbis-dev \ libvo-amrwbenc-dev \ libunwind-dev \ libvulkan-dev \ libwayland-dev \ libx264-dev \ libx11-dev \ libxext-dev \ libxinerama-dev \ libxkbcommon-dev \ libxpresent-dev \ libxrandr-dev \ libxss-dev \ libxv-dev \ libxvidcore-dev \ libxxhash-dev \ x11proto-core-dev源码编译libplacebo在Ubuntu 24.04，libplacebo也可以从官方仓库安装MPV可以使用的最低版本了。sudo apt-get install libplacebo-dev[collapse status="false" title="老的源码编译步骤"]按官方介绍，libplacebo是MPV的基础库。按官方README来编译安装，meson build那一步能看到可选特性中d3d11, glslang, libdovi, shaderc, vk-proc-addr这几项是NO，用apt安装glslang-dev会导致更多的怪问题，libdovi是杜比音效相关的库，一般用不到，shaderc可以去这里的Downloads部分下载，然后把对应的文件夹放进/usr/local/，这套东西解压了有2.8G……git clone --recursive https://code.videolan.org/videolan/libplacebo cd libplacebo mkdir build && cd build meson .. ninja sudo ninja install[/collapse]源码编译MPV终于到了最后一步，就很简单了。git clone https://github.com/mpv-player/mpv.git cd mpv meson setup build meson compile -C build sudo meson install -C build最后输入mpv或者直接找个视频双击看看能不能打开，如果命令行mpv提示类似mpv: error while loading shared libraries: libplacebo.so.277，需要用sudo ldconfig刷新一下shared libraries。官方一键安装教程这里也记录下一键安装教程，参见官方的安装教程。git clone https://github.com/mpv-player/mpv-build.git cd mpv-build ./rebuild -j4 sudo ./install非常的简单，提示有什么依赖缺失就装什么，或者去mpv-build/debian/control把所有要装的都装了。像libdav1d这种要自己编译的参考上面的FFmpeg安装。后续小问题后来安装obs-studio的时候提示找不到ffmpeg_aac编码器，检查具体log后发现是找不到libsndio.so.7.0，执行sudo apt-get install libsndio7.0 libsndio-dev --reinstall后解决，可能又是删除那个坑比ffmpeg的收费PPA时没删干净造成的吧。
简介Zotero是一个开源的文献管理软件，可以跨平台同步文献库，这里记录一下个人的配置。安装本体Windows上安装Zotero直接去官网下载安装就行了，Linux下则要下载后自行解压到想放的文件夹里，并自己生成桌面图标。参考官方说明。需要注意的是，Windows的Zotero可以自动更新，但Ubuntu的可能有bug，自动更新从没成功过，需要自己重新下载解压覆盖，并再生成一次桌面图标。插件很有用的两个插件是ZotMoov和Better BibTex，从各自的官网下载xpi文件，然后Zotero选择Tools -> Add-ons，点右上角的齿轮，选择Install Add-on From File，选择刚下载的文件即可安装。设置作为一个开源软件，想用得舒服就得自己去折腾配置。以下为个人的工作流：用Zotero官方帐号同步文献库的条目，但免费版的只有300M的存储空间，所以不同步PDF文档。用OneDrive等网盘来同步PDF，利用ZotFile来管理附件，把所有文档集中放在OneDrive的一个文件夹里。引用时用Better BibTex来导出各个条目的BibTex，最后在Latex里微调。基础设置基础设置在上面的Edit -> Preferences里：General -> Open PDF using选择System Default，自带的不好用。Sync -> Settings，登录注册的Zotero帐号，勾选Sync automatically和Sync full-text content，下面的File Syncing都不勾选。Search不变。Export的Item Format选择Better BibTex。Cite不变。Advanced -> Files and Folders -> Base directory选择OneDrive里要放PDF的文件夹，下面的Data Directory Location可以按需修改。Zotero7增加了自带的文件重命名功能，在General -> File Renaming里，勾选Rename linked files，规则我设置的是“年份_标题_作者et al.pdf”，如下。{{ year suffix="_" }}{{ title truncate="150" suffix="_" replaceFrom=": " replaceTo=" - " }}{{ firstCreator replaceFrom="et al." replaceTo="et al" }}ZotMoov设置首先Directory to Move/Copy Files To设置为跟基础设置里一样的OneDrive文件夹，File Behavior选择Move，下面三个Automatically的设置都勾上，Subdirectory String使用默认的{%c}，即按文章类别（collection）分文件夹。然后我还在Advanced标签卡里的Config Editor改了几个选项，搜索zotmoov，把extensions.zotmoov.add_zotmoov_tag设置为false，禁止插件给所有PDF都打个tag。还有个extensions.zotmoov.rename_title可以根据需求改为false，如果选true会把PDF在Zotero里的标题（不是文件名）改成跟文件名一样的格式，我选择false，之后自己改文件标题是正文还是supplementary material。目前ZotMoov还不支持导入附件时手动添加一个suffix，例如我用ZotFile时会给supplementary material的文件名加个(supp)的后缀，用ZotMoov似乎无法实现。文件名只能使用上面设置的自动命名规则，可以自己手动修改Zotero里的文件标题为SUPP。[collapse status="false" title="ZotFile设置"]2025更新： ZotFile和最新版的Zotero 7不兼容，作者似乎也没有计划更新，因此以下的设置已不适用于最新版的Zotero。可以使用ZotMoov作为替代。ZotFile的设置在Tools -> ZotFile Preferences里：General Settings -> Location of Files的Custom Location选择跟基础设置里一样的OneDrive文件夹。勾选Use subfolder definded by，填入%c，指按文章类别（collection）分文件夹。Tablet Settings不用管。Renaming Rules是对导入的PDF文档的命名规则，个人是设置为“年份_标题_作者 (备注).pdf”，论文本体备注一般留空，supplementary material会在备注里填supp。具体设置如下：Format for all Item Types except Patents以及Format for Patents都填{%y_}{%t_}{%a}，下面Additional Settings里，Delimiter between multiple authors设为下划线_，勾选Add user input to filename.， Default is留空，勾选Maximum length of title填80，Maximum number of authors填2，Numbers of authors to display when authors are omitted填1，最后Add suffix when authors are omitted填et al。其他的没提到选项都不勾选。Advanced Settings里应该不用改。[/collapse]Better BibTex设置Better BibTex的设置在Tools -> Better BibTex Preferences：Citation keys的Citation key formula设为(((extra('field').clean.len + ":") > 1) || "") + (ShortTitle.clean || shorttitle(3,3)) + year这样设置可以在Zotero的extra栏里填入“field: xxx”，导出时生成的bibtex key会变成“xxx:”加上文章标题的短标题或者前三个词加上发表年份，例如"Attention is All You Need"的key是"nlp:AttentionAllYou2017"。下面的Force citation key to plain text不勾选，Enable citation key search可以选。 Export选项卡里，BibTex勾选Export unicode as plain-text latex commands，Add URLs to BibTex export选择in the 'url' field；postscript里加入一段把ArXiv文章从journal改为misc的代码：if (Translator.BetterBibTeX) { tex.remove("file"); tex.remove("abstract"); tex.remove("annotation"); if (tex.entrytype === "article" && zotero.arXiv) { if (tex.has.journal && zotero.arXiv.source === "publicationTitle") { tex.add({name: "howpublished", value: zotero.publicationTitle}); tex.remove("journal"); } if (!tex.has.journal) tex.entrytype = "misc"; } }Export -> Miscellaneous取消勾选Apply title-casing to titles，同时也不勾选Apply case-protection to capitalized words by enclosing them in braces。 Import选项卡里选择no (import titles as-is)，导入条目的时候一般标题里该大写的都会自动大写，不用这软件教我怎么设置大小写，更不能信任这些自动大小写转换，最终还是得在bib里一个一个改。