Memos是什么:一个开源的、支持私有化部署的碎片化知识卡片管理工具。可以说是支持 Docker 自部署的 flomo
官网:https://usememos.com/
仓库地址:https://github.com/usememos/memos
Docker部署
1
| docker run -d --name memos -p 5230:5230 -v ~/.memos/:/var/opt/memos neosmemo/memos:latest
|
Docker Compose部署
1.创建 Memos 工作目录
1 2
| mkdir memos && cd memos vi docker-compose.yaml
|
2.编写 docker-compose.yaml
文件:
1 2 3 4 5 6 7 8 9 10
| version: "3.0" services: memos: image: neosmemo/memos:latest restart: always container_name: memos volumes: - ~/.memos/:/var/opt/memos ports: - 5230:5230
|
更多参考:docker-compose.yaml
3.执行命令,Memos
后端程序将运行在 http://localhost:端口号
通过访问 localhost:5230
即可打开 Memos,首次安装会提示注册用户,请记牢您的而密码。数据文件默认存储在 ~/.memos
中。
PS:如果使用vultr,注意由于默认vultr什么端口都没有开放,安装后要记得要开放5230端口:
1
| iptables -I INPUT -p tcp --dport 5230 -j ACCEPT
|
4.更新。删除现有容器,拉取最新镜像,然后重新创建容器即可。
Docker Compose
1 2 3 4
| cd memos docker-compose down docker-compose pull docker-compose up -d
|
可选命令:
cp -r /root/.memos /root/.memos.archive
事先备份,以防万一(将/root/.memos
文件夹下的数据库复制到/root/.memos.archive
文件夹下)
docker image prune
用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像
提示:
1 2
| WARNING! This will remove all dangling images. Are you sure you want to continue? [y/N]
|
Docker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| docker stop memos
docker rm -f memos
cp -r /root/data/docker_data/memos/.memos /root/data/docker_data/memos/.memos.archive
docker pull neosmemo/memos:latest
docker run -it -d \ --name memos \ --publish 5230:5230 \ --volume /root/data/docker_data/memos/.memos/:/var/opt/memos \ neosmemo/memos:latest \ --mode prod \ --port 5230
|
/root/data/docker_data/memos/.memos/
这个可以换成你自己服务器的路径;
5.卸载
1 2 3 4 5
| docker stop memos
docker rm -f memos # 停止容器,此时不会删除映射到本地的数据
rm -rf /root/data/docker_data/memos # 完全删除映射到本地的数据
|
6.一些 Docker Compose 常用命令:
1 2 3 4 5
| docker-compose restart # 重启容器 docker-compose stop # 暂停容器 docker-compose down # 删除容器 docker-compose pull # 更新镜像 docker-compose exec artalk bash # 进入容器
|
配置域名访问
1
| vi /etc/nginx/conf.d/memos.conf
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| server { listen 80; server_name me.bore.vip; location / { proxy_pass http://127.0.0.1:5230; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-cache; expires 12h; } location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; allow all; root /data/wwwroot/me.bore.vip/; } }
|
重启Nginx:systemctl restart nginx
申请SSL证书
参考:Nginx 配置 ssl 证书
1.新建文件夹:
1
| mkdir -p /data/wwwroot/me.bore.vip
|
2.申请证书
1
| sudo apt-get install letsencrypt -y
|
1
| certbot certonly --webroot -w /data/wwwroot/me.bore.vip -d me.bore.vip -m 455343442@qq.com --agree-tos
|
3.编辑 Nginx
(1)未启用端口复用:
1
| vi /etc/nginx/conf.d/memos.conf
|
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
| server { listen 80; listen 443 ssl http2; server_name me.bore.vip; root /data/wwwroot/me.bore.vip;
# SSL setting ssl_certificate /etc/letsencrypt/live/me.bore.vip/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/me.bore.vip/privkey.pem; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=31536000";
# proxy to 5230 location / { proxy_pass http://127.0.0.1:5230; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; # cache add_header Cache-Control no-cache; expires 12h; }
location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; allow all; root /data/wwwroot/me.bore.vip/; } }
|
(2)启用端口复用:
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
| server { listen 80; listen 127.0.0.1:1314 ssl http2 proxy_protocol; set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; port_in_redirect off; server_name me.bore.vip; root /data/wwwroot/me.bore.vip; if ($host != 'me.bore.vip' ) { rewrite ^/(.*)$ https://me.bore.vip/$1 permanent; }
ssl_certificate /etc/letsencrypt/live/me.bore.vip/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/me.bore.vip/privkey.pem; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=31536000";
location / { proxy_pass http://127.0.0.1:5230; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-cache; expires 12h; }
location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; allow all; root /data/wwwroot/me.bore.vip/; } }
|
4.重启Nginx、xr
证书自动续期
参考:自动续期
安卓快捷方式发送Memos
参考:安卓手机上快捷方式发送
注意:
1.变量只添加一个content
即可
2.响应体/响应参数
,选择自定义类型
,Content-Type 填写 application/json
,请求体填写:(最好不要直接点复制按钮复制代码,直接拖动选择所有行代码,这样张贴就会保留空格)
1 2 3
| { "content": "{content}" }
|
注意:上面的{content}
需要先删除,然后点击旁边的 {}
插入变量(插入的变量颜色是蓝色)。不能直接填写!!!
3.#tag
后面必须有个空格才能创建tag
首页轮播
API 调用最新 10 条 memos 在博客首页轮播显示。
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
| <div id="bber-talk"></div> <style> #bber-talk{display:-webkit-flex;display:flex;width:100%;line-height:35px;height:45px;max-width:760px;text-align:left;padding:5px 15px;margin:20px 0;position: relative;background-color: var(--light-header);border-radius:8px;font-size:15px;overflow:hidden;} #bber-talk svg{fill: currentColor;vertical-align: middle;display: inline;margin-right:5px;margin-top: -4px;} .talk-wrap{width:100%;} .talk-list{margin: 0;height: 35px;} .talk-list li {list-style:none;margin-bottom:10px;width: 100%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;zoom: 1;} .talk-list li .datetime{margin-right:2px;} .talk-list li a{text-decoration:none;} .dark-theme #bber-talk{background-color: var(--dark-header);} .dark-theme .talk-list{color: var(--dark-color);} @media only screen and (max-width:683px) { #bber-talk{margin:2em 1em 1em;width:94%;} } </style> <script src="https://cdn.jsdelivr.net/npm/dayjs@1.11.5/dayjs.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/dayjs@1.11.5/locale/zh-cn.js"></script> <script src="https://cdn.jsdelivr.net/npm/dayjs@1.11.5/plugin/relativeTime.js"></script> <script>dayjs.locale('zh-cn');dayjs.extend(window.dayjs_plugin_relativeTime)</script> <script> var bbUrl = "https://me.edui.fun/api/memo?creatorId=101&limit=10" fetch(bbUrl).then(res => res.json()).then( resdata =>{ var result = '',resultAll="",data = resdata.data console.log(data) for(var i=0;i < data.length;i++){ var bbTime = dayjs.unix(data[i].createdTs).fromNow() var bbCont = data[i].content var newbbCont = bbCont.replace(/(https?:[^:<>"]*\/)([^:<>"]*)(\.((png!thumbnail)|(png)|(jpg)|(webp)|(jpeg)|(gif))(!blogimg)?)/g,' 🌅 ') var newbbCont = newbbCont.replace(/\bhttps?:\/\/(?!\S+(?:jpe?g|png|bmp|gif|webp|jfif|gif))\S+/g,' 🔗 ') result += `<li class="item"><span class="datetime">${bbTime}</span>: <a href="https://me.edui.fun/u/101" target="_blank">${newbbCont}</a></li>`; } var bbDom = document.querySelector('#bber-talk'); var bbBefore = `<span class="index-talk-icon"><svg viewBox="0 0 1024 1024" width="21" height="21"><path d="M184.32 891.667692c-12.603077 0-25.206154-2.363077-37.809231-7.876923-37.021538-14.966154-59.864615-49.624615-59.864615-89.009231v-275.692307c0-212.676923 173.292308-385.969231 385.969231-385.969231h78.76923c212.676923 0 385.969231 173.292308 385.969231 385.969231 0 169.353846-137.846154 307.2-307.2 307.2H289.083077l-37.021539 37.021538c-18.904615 18.116923-43.323077 28.356923-67.741538 28.356923zM472.615385 195.347692c-178.018462 0-322.953846 144.935385-322.953847 322.953846v275.692308c0 21.267692 15.753846 29.144615 20.48 31.507692 4.726154 2.363077 22.055385 7.876923 37.021539-7.08923l46.473846-46.473846c6.301538-6.301538 14.178462-9.452308 22.055385-9.452308h354.461538c134.695385 0 244.184615-109.489231 244.184616-244.184616 0-178.018462-144.935385-322.953846-322.953847-322.953846H472.615385z"></path><path d="M321.378462 512m-59.076924 0a59.076923 59.076923 0 1 0 118.153847 0 59.076923 59.076923 0 1 0-118.153847 0Z"></path><path d="M518.301538 512m-59.076923 0a59.076923 59.076923 0 1 0 118.153847 0 59.076923 59.076923 0 1 0-118.153847 0Z"></path><path d="M715.224615 512m-59.076923 0a59.076923 59.076923 0 1 0 118.153846 0 59.076923 59.076923 0 1 0-118.153846 0Z"></path></svg></span><div class="talk-wrap"><ul class="talk-list">` var bbAfter = `</ul></div>` resultAll = bbBefore + result + bbAfter bbDom.innerHTML = resultAll; }); setInterval(function() { for (var s, n = document.querySelector(".talk-list"), e = n.querySelectorAll(".item"), t = 0; t < e.length; t++) setTimeout(function() { n.appendChild(e[0]) },1000) },1000) </script>
|
单页部署代码
已做 js 文件调用处理,找个页面丢入以下 html + js + css 即可。当然,得先部署个 Memos,或者,找个好朋友开个 id 也可以。
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="bber"></div> <script type="text/javascript"> var bbMemos = { memos : 'https://me.edui.fun/', limit : '', creatorId:'' , domId: '', } </script> <script src="https://immmmm.com/bb-lmm.js"></script> <script src="https://fastly.jsdelivr.net/gh/Tokinx/ViewImage/view-image.min.js"></script> <script src="https://fastly.jsdelivr.net/gh/Tokinx/Lately/lately.min.js"></script>
|
样式代码供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #bber{margin-top:1em;} .timeline ul {margin:0;} .timeline ul li {background:#3b3d42;list-style-type:none;position:relative;width:3px;margin-left:1em;padding:0.8em 0 2em;} .timeline ul li::after {transform: rotate(45deg);content:'';background-color: #3b3d42;display: block;position: absolute;top: 10px;left: -5px;width: 0.8em;height: 0.8em;outline:15px solid #fff;} .timeline ul li div {position:relative;top:-13px;left:1em;width:670px;padding:0px 16px 0px;} .timeline ul li p.datatime{color: #fafafa;font-size: 0.75em;font-style: italic;background-color: #3b3d42;display: inline-block;padding:0.25em 1em 0.2em 1em;} .timeline ul li p.datacont{white-space: pre-wrap;margin:0.65em 0 0.3em;} .timeline ul li p.datacont img{display:block;max-height:340px !important;} .timeline ul li p.datacont img[src*="emotion"]{display:inline-block;width:auto;} .timeline ul li p.datafrom{color: #aaa;font-size: 0.75em !important;font-style: italic;} .timeline ul li p{margin:0;font-size:16px;letter-spacing:1px;color: #3b3d42;} .timeline ul li p.datacont .img{cursor: pointer;border:1px solid #3b3d42;max-width:20rem;margin:6px 0 6px 0;} button{border-radius:0;} .dark-theme .timeline ul li div p{color:#fafafa;} .dark-theme .timeline ul li div p svg{fill:#fafafa;} .dark-theme .timeline ul li p.datafrom{color: #aaa;} .dark-theme .timeline ul li{background:#3b3d42;} .dark-theme .timeline ul li::after{outline: 15px solid #2f2f2f;} @media (max-width:860px) { .timeline ul li{margin-left:0;} .timeline ul li div{width:calc(100vw - 75px);left:30px;} }
|
定时备份数据库
参考:halo 定时备份的方法
总结
感觉还是小康speak和Butterfly主题更搭,况且小康speak也可以独立部署,所以还是用前者吧!
参考链接
Hi,Memos
哔哔点啥 By Memos
搭建属于你自己的 flomo 应用 :Memos
好玩儿的Docker项目