搭建图床

一直想搭建一个图床,毕竟自己的是可控的,备份很方便、数据很安全。由于不知道自己什么时候会更换vps,而且这些图床对web环境要求比较严苛,所以使用了Docker安装的图床。

docker的优点很多:

  1. 不用搭建那麻烦死人的web环境,我使用lnmp和宝塔均搭建失败。

  2. 换机时只需要打包对应的文件即可,十分钟后又是一条‘好汉’。

安装过程中会遇到的问题:

  1. 使用vim/vi粘贴docker-compose.yaml会出现格式错乱

解决方案:Esc + : 输入set paste

  1. 使用nginx反代后在图床里看到是本地IP(172.23.0.1)连接的,而在nginx的访问日志里的IP是CDN的IP ??

解决方案:

  1. nginx日志参考我前面写的:
    传送门1
    Nginx获取用户真实ip

  2. 需要挂载functions.php

需要先 docker cp chevereto:/var/www/html/lib/G/functions.php /home/<username>/chevereto/lib/G/functions.php

/home//chevereto/lib/G/functions.php:/var/www/html/lib/G/functions.php:rw

在大约852行修改为 return $_SERVER['HTTP_X_FORWARDED_FOR'];

如果使用的CDN是CF的话可以改成 HTTP_CF_CONNECTING_IP,但是如果后期不适应CF的话还需要改回原来的代码,建议改成 HTTP_REAL_IP 如果使用的不是CF就会自动把IP设置为 SERVER_ADDR

3.

1
2
3
4
5
6
7
8
9
10
11
12
#nginx.conf/site.conf中的非server中写入一下
map $HTTP_CF_CONNECTING_IP $real{
"" $remote_addr;
~^(?P<firstAddr>[0-z\.]+),?.*$ $HTTP_CF_CONNECTING_IP;
}

#img.xxx.conf中增加
proxy_set_header REAL-IP $real;

#在functions.php大约852行修改为'HTTP_REAL_IP'
nginx -t
nginx -s reload

​ 我们需要明白 REAL-IP 代表变量,HTTP_REAL_IP 代表变量的值
​ 推荐第三种,如果使用cf那么获得的ip是HTTP_CF_CONNECTING_IP,如果不使用cf而是直连,那么获得的ip是remote_addr

最后

1
docker-compose down && docker-compose up -d
  1. 解决Chevereto图床上传大图片提示Internal Server error

php.ini

1
2
3
4
5
max_execution_time = 1000
max_input_time = 1000
memory_limit = 1024M
upload_max_filesize = 100M
post_max_size = 100M

nginx.conf

1
client_max_body_size 64M;
1
2
nginx -s reload
docker-compose down && docker-compose up -d

1.chevereto-free

1
2
mkdir -p /home/<username>/chevereto/app
vim /home/<username>/chevereto/app/php.ini

php.ini

1
2
3
4
5
max_execution_time = 1000
max_input_time = 1000
memory_limit = 1024M
upload_max_filesize = 100M
post_max_size = 100M
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
version: '3'
services:
db:
image: mariadb
container_name: mariadb_chevereto
volumes:
- /home/<username>/chevereto/db_cheve:/var/lib/mysql:rw
# username改为你想要设置的用户名
restart: always
privileged: true
networks:
- private
environment:
MYSQL_ROOT_PASSWORD: passwd
# 数据库主密码
MYSQL_DATABASE: chevereto
MYSQL_USER: chevereto
MYSQL_PASSWORD: cheve_passwd
# 修改为你想要的密码

chevereto:
depends_on:
- db
image: nmtan/chevereto:1.4.1
# 最新版不支持中文
container_name: chevereto
restart: always
networks:
- private
environment:
CHEVERETO_DB_HOST: db
CHEVERETO_DB_USERNAME: chevereto
CHEVERETO_DB_PASSWORD: cheve_passwd
# 密码与上述一致
CHEVERETO_DB_NAME: chevereto
CHEVERETO_DB_PREFIX: chv_
volumes:
#username改为你想要设置的用户名
- /home/<username>/chevereto/images:/var/www/html/images:rw
- /home/<username>/chevereto/app/php.ini:/usr/local/etc/php/php.ini:ro
#这两个是相册的设置
#- /home/<username>/chevereto/content:/var/www/html/content:rw
#- /home/<username>/chevereto/app/routes:/var/www/html/app/routes:rw
#这个是get_real_ip
- /home/<username>/chevereto/lib/G/functions.php:/var/www/html/lib/G/functions.php:rw

ports:
- 127.0.0.1:4578:80
# 修改为想要的端口
# 设置为127.0.0.1,那么我们只需要通过nginx反向代理访问,直接使用ip访问不了

networks:
private:


之前比较担心数据库的端口3306会与之前创建的数据库相冲突,查询后发现db和cheverteo在一个名为compose_private的本地网络中,其中mariadb的端口3306并没有外显出来,只是在private这个网络段里可以使用。

所以我们可以只需要关闭4578端口就行了。
只需要改成 127.0.0.1:4578:80 就行了。

我们也可以在nginx_conf中设置如果 $host 为IP格式就返回403。

1
2
3
4
if ($host ~ "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}") 
{
return 403;
}

这样使用api上传图片,用户就变成了游客,看着很不舒服

content文件夹主要与系统和用户设置有关;而app/routes则与相册的设置有关,我们需要把这两个文件夹从容器中映射出来。

首先进入容器中,打包这两个文件夹,然后移动到之前已经映射的images文件夹内,然后回到shell,将这两个文件夹解压并映射。

直接使用 docker cp 命令复制即可,无需下面复杂的操作

1
2
3
4
5
6
7
8
9
10
11
12
docker exec -it chevereto /bin/bash
tar czvf content.tar.gz ./content
tar czvf routes.tar.gz ./app/routes/
mv content.tar.gz routes.tar.gz ./images
CRTL + A + D
cd /home/<username>/chevereto/images
mv content.tar.gz routes.tar.gz ..
tar xzvf content.tar.gz
tar xzvf routes.tar.gz
rm content.tar.gz routes.tar.gz
# 然后取消最后两行注释,打开docker-compose.yaml的路径
docker-compose up -d

然后修改route文件夹下route.api.php

1
2
3
4
5
vim /home/<username>/chevereto/app/routes/route.api.php
# 使用命令set nu
# 在大约105行,注释这一行 # $uploaded_id = CHV\Image::uploadToWebsite($source);
# 然后粘贴后修改为你的用户名和相册ID
$uploaded_id = CHV\Image::uploadToWebsite($source, 'test', array('album_id'=>5));

test为你的用户名,在右上角

album_id为你的相册ID,建议新建一个相册,然后点击详细信息。

nginx配置文件:

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
server
{
listen 80;
#listen 443 ssl;
server_name img.demo.com;
#ssl_certificate crt/pem;
#ssl_certificate_key key;

# 禁止爬虫,if语句必须放在server或者location范围内,不能放在http范围内。
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot" ) {
return 403;
}
# 上传大图片开启
client_max_body_size 64M;

# 禁止IP访问
if ($host ~ "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")
{
return 403;
}

# 对一些静态资源设置缓存时间,务必放到 location / 的上面
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|webp)$
{
proxy_pass http://127.0.0.1:4578;
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 REMOTE-HOST $remote_addr;
#proxy_set_header REAL-IP $real;
add_header X-Cache $upstream_cache_status;
# 过期时间为10天,图片文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
add_header Cache-Control max-age=864000;
}

location /
{
proxy_pass http://127.0.0.1:4578;
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 REMOTE-HOST $remote_addr;
#proxy_set_header REAL-IP $real;
# 此方法可能不适合域名反代
add_header X-Cache $upstream_cache_status;
# no-cache在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证 (协商缓存验证)。
# 指定 no-cache 或 max-age=0, must-revalidate 表示客户端可以缓存资源,每次使用缓存资源前都必须重新验证其有效性。这意味着每次都会发起 HTTP 请求,但当缓存内容仍有效时可以跳过 HTTP 响应体的下载。
add_header Cache-Control no-cache;
}

access_log /www/wwwlogs/img.demo.com.log; #日志可以不写
error_log /www/wwwlogs/img.demo.com.error.log;
}

解释一下nginx的配置信息

server_name:表示对应的域名,如果有多个可以中间以空格隔开

每个if语句的if后面要有一个空格,例:if ($ 。不要轻易使用if。

第一个location的作用:如果匹配到以 (gif|jpg|jpeg|png|bmp|swf|webp) 结尾的就不会继续向下匹配,在这个location中我们可以增加一个响应头告诉CDN或者浏览器对这个资源的缓存时间。

第二个location的作用:起到一个收底的作用,因为图床中不止有图片静态资源,所以这个里面加了一个响应头 no-cache ,可以缓存资源但是要验证资源的有效性。

如果这两个location更换位置,那么location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|webp)$,则不会起作用,因为 location / 能匹配一切。

add_header Cache-Control max-age=864000; 写在 location / 里面虽然不会出现问题,但是感觉很奇怪。

2.EasyImages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3.3'
services:
easyimage:
image: 'ddsderek/easyimage:latest'
container_name: 'easyimage'
restart: 'unless-stopped'
ports:
- '127.0.0.1:4579:80'
# 修改为想要的端口
environment:
- 'TZ=Asia/Shanghai'
- 'PUID=1000'
- 'PGID=1000'
volumes:
- /home/<username>/easyimage/config:/app/web/config
- /home/<username>/easyimage/i:/app/web/i
# - /home/<username>/easyimage/admin/admin.inc.php:/app/web/admin/admin.inc.php

需要先将 admin.inc.php 复制到 /home/<username>/easyimage/admin/ 再取消注释的最后一行,目的是修改图床里面显示的IP地址。

1
2
docker cp easyimage:/app/web/admin/admin.inc.php /home/<username>/easyimage/admin/admin.inc.php
# 替换username为你的路径

如果在 nginx.conf 里设置 map ,那么就修改 admin/admin.inc.php 的大约第937行 $_SERVER["SERVER_ADDR"] 改为 $_SERVER["HTTP_REAL_IP"] ,如果没有添加 map 就改为 $_SERVER["HTTP_CF_CONNECTING_IP"]

为了安全建议设置成这样,然后将默认全部api禁用

nginx配置文件:

这个内容请参考上面那个,它们具有很大的相似性。

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
server
{
listen 80;
server_name image.demo.com;
# 改为你想设置的域名

location /
{
proxy_pass http://127.0.0.1:4579;
proxy_set_header Host $host;
proxy_set_header remote_addr $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
# 此方法可能不适合域名反代
add_header X-Cache $upstream_cache_status;
add_header Cache-Control no-cache;
}

#禁止爬虫,if语句必须放在server或者location范围内,不能放在http范围内。
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot" ) {
return 403;
}

access_log /www/wwwlogs/image.demo.com.log; #日志可以不写
error_log /www/wwwlogs/image.demo.com.error.log;
}
1
2
chmod -R 755 /home/usermame/easyimage/i
chown -R www:www /home/usermame/easyimage

3.使用API上传图片

PicGo有app和cli两种方式,我觉得还是chevereto使用cli比较好用,设置简单。

  1. app

最简单

可能需要node.js环境

Typora有两种上传图片的方式:

  1. 每粘贴或复制一张图片点击一次上传。
  2. 在编辑完整个文档之后,点击格式->图像->上传所有本地图片来一次性的将整个文档的图片都上传。

a. 对于chevereto

插件设置里面搜索chevereto

url: http://域名/api/1/upload

key: http://域名/dashboard/settings/api

b. 对于EasyImages

插件设置里面搜索web-uploader,可能需要node.js环境

1
2
3
4
API地址: https://域名/api/index.php // 输入你的网站api地址 
POST参数名: image
JSON路径: url
自定义Body: {"token":"1c17b11693cb5ec63859b091c5b9c1b2"} // 这里输入你网站生成的token

token建议删除所有默认的,然后新建一个,https://域名/admin/admin.inc.php,

  1. cli:

先安装node.js环境

1
2
npm install picgo -g
picgo install chevereto

CMD打开

1
2
3
notepad %HOMEPATH%\.picgo\config.json
#或者
notepad %UserProfile%\.picgo\config.json

a. 对于chevereto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"picBed": {
"current": "chevereto",
"uploader": "chevereto",
"chevereto": {
"key": "上面从api里面获得的密钥",
"source_param": "source",
"url": "https://域名/api/1/upload",
"url_param": null
}
},
"picgoPlugins": {
"picgo-plugin-chevereto": true
}
}

b. 对于EasyImage

1
2
picgo install web-uploader
picgo set uploader # 选择web-uploader

CMD打开

1
notepad %HOMEPATH%\.picgo\config.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"picBed": {
"uploader": "web-uploader",
"current": "web-uploader",
"web-uploader": {
"url": "https://域名/api/index.php",
"paramName": "image",
"jsonPath": "url",
"customHeader": "",
"customBody": "{\"token\":\"1c17b11693cb5ec63859b091c5b9c1b2\"}"
}
},
"picgoPlugins": {
"picgo-plugin-web-uploader": true
}
}

  1. python

Docker系列五自建图床 | 君匡博客 (clzly.xyz)

这个博主写的python方案看着不错,可以试一试。

引用与参考:

nmtan/chevereto - Docker Image | Docker Hub

ddsderek/easyimage - Docker Image | Docker Hub

keven1024/chevereto-free-multi-language: multi-language chevereto ( 支持多国语言的chevereto-free ) (github.com)

rodber/chevereto-free: Self-hosted Image Hosting solution. Start your own Flickr/imgur alternative with your own rules. (github.com)

Docker系列五自建图床 | 君匡博客 (clzly.xyz)

icret/EasyImages2.0: 新版简单强大无数据库的图床2.0版 演示地址: (github.com)

简介 · 简单图床-EasyImage2.0 使用手册 · 看云 (kancloud.cn)

修改Chevereto的API上传相册和用户_飞逝17的博客-CSDN博客

get_real_ip-github

php中$_SERVER参数HTTP_X_FORWARDED_FOR & REMOTE_ADDR与获取IP

Cache-Control MDN


搭建图床
https://shyi.org/posts/58867/
作者
Shyi
发布于
2022年6月13日
更新于
2024年9月7日
许可协议