Ubuntu18.04 Nginx+Lua+GraphicsMagick图片缩放

8.9k 词

自己搭建的图片服务器,有图片缩放的需求,大致思路是可以使用nginx调用lua,使用GraphicMagick的命令来做图片缩放

说明

文件夹规划

lua.jaychang.cn(如/var/filebase)

1
2
3
4
5
6
7
8
9
10
11
12
13
jaychang@nginx:~$ tree /var/filebase/
/var/filebase/
├── avatar.png
├── cache
│   └── thumb
│   ├── avatar.png_100x100.png
│   └── upload
│   ├── 1.png_100x100.png #固定高和宽
│   ├── 1.png_400-.png # 定高
│   └── 1.png_800-.png # 定宽
└── upload
├── 1.png
4 directories, 8 files

其中img.xyz.com为图片站点根目录
cache/thumb为缩略图存放目录
upload目录存放上传的图片

链接地址对应关系

原图访问地址:http://img.xyz.com/upload/1.png
缩略图访问地址:http://img.xyz.com/upload/1.png_100x100.png 即为宽100,高100
自动宽地址: http://img.xyz.com/upload/1.png_-400.png 用”-“表示自动,即为高400,宽自动
自动高地址: http://img.xyz.com/upload/1.png_800-.jpg 用”-“表示自动,即为宽800,高自动

访问流程

首先判断缩略图是否存在,如存在则直接显示缩略图;
缩略图不存在,则判断原图是否存在,如原图存在则拼接graphicsmagick(gm)命令,生成并显示缩略图,否则返回404

所需软件

  • lua-5.3.5.tar.gz
  • LuaJIT-2.0.5.tar.gz
  • nginx-1.14.2.tar.gz
  • nginx模块:lua-nginx-module-0.10.15.tar.gz

    lua-nginx-module 依赖于 LuaJIT 和 ngx_devel_kit。LuaJIT 需要安装,ngx_devel_kit 只需下载源码包,在 Nginx 编译时指定 ngx_devel_kit 目录

  • nginx模块:nginx-http-concat
  • nginx模块:ngx_devel_kit
  • nginx模块:nginx-http-concat
1
2
3
4
5
6
7
curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
curl -R -O http://luajit.org/download/LuaJIT-2.0.5.tar.gz
curl -R -O http://nginx.org/download/nginx-1.14.2.tar.gz
curl -R -O https://github.com/openresty/lua-nginx-module/archive/v0.10.15.tar.gz
curl -R -O https://github.com/openresty/lua-resty-core/archive/v0.1.17.tar.gz
curl -R -O https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
git clone git@github.com:alibaba/nginx-http-concat.git

安装依赖

1
2
3
apt-get install -y gcc g++ make

apt-get install libreadline-dev libpcre3 libpcre3-dev openssl libssl-dev zlib1g zlib1g-dev libgeoip-dev -y

编译安装Lua LuaJIT

编译安装Lua

1
2
3
4
curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
tar zxf lua-5.3.5.tar.gz
cd lua-5.3.5
make linux test

编译安装LuaJIT

1
2
3
4
5
6
7
8
curl -R -O http://luajit.org/download/LuaJIT-2.0.5.tar.gz
tar -zxvf LuaJIT-2.0.5.tar.gz
cd LuaJIT-2.0.5
make -j2 && make install
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.0
echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf
ldconfig

安装GraphicsMagick

1
apt install -y graphicsmagick

直接用apt来安装的话,可以免去安装 jpg,png 等图片库依赖

创建用户及相应目录

1
2
3
4
groupadd nginx && useradd nginx -g nginx -s /sbin/nologin -M

mkdir -p /var/tmp/nginx/client_body_temp
mkdir -p /var/tmp/nginx/uwsgi_temp

创建用户也可以用以下命令:

1
groupadd nginx && useradd nginx -g nginx -s /bin/false -M

编译安装nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
./configure --prefix=/usr/local/nginx 
--user=nginx --group=nginx
--sbin-path=/usr/sbin/nginx
--with-pcre
--with-http_realip_module
--with-http_gzip_static_module
--with-http_stub_status_module
--with-http_v2_module
--with-http_flv_module
--with-http_ssl_module
--with-http_addition_module
--with-http_geoip_module
--add-module=/usr/local/src/lua-nginx-module-0.10.15
--add-module=/usr/local/src/ngx_devel_kit-0.3.0
--add-module=/usr/local/src/nginx-http-concat
--http-scgi-temp-path=/var/tmp/nginx/cgi_temp
--http-client-body-temp-path=/var/tmp/nginx/client_body_temp
--http-proxy-temp-path=/var/tmp/nginx/proxy_temp
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp
--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp
--http-log-path=/var/log/nginx/access.log
--error-log-path=/var/log/nginx/error.log
1
make -j 2 && make install

注意:动态加载模块,Nginx官方的load_module指令,详细文档参考1
参考2
还有–with-http_spdy_module 已经改为–with-http_v2_module了
,如果不用geo的话,编译的时候可以不加–with-http_geoip_module,可以不安装libgeoip-dev

测试nginx

1
nginx -t

如果出现以下错误(没有报错就不用做以下操作了)

1
2
root@ubuntu:/usr/local/src/nginx-1.14.2# nginx -t
nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory

执行以下命令即可

1
2
echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf
ldconfig

修改nginx.conf配置文件

将nginx.conf配置文件中的server{}段配置注释掉

加一行配置,以便读取/usr/local/tengine/conf.d目录下所有后缀为.conf的配置文件

1
include ../conf.d/*.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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
user nginx;
worker_processes 4;
worker_cpu_affinity 1000 0100 0010 0001;
error_log /var/log/nginx/error.log error;
pid /usr/local/nginx/logs/nginx.pid;
worker_rlimit_nofile 65535;
events
{
use epoll;
worker_connections 65535;
}
http
{
lua_load_resty_core off;
limit_conn_zone $binary_remote_addr zone=one:10m;
limit_conn_zone $server_name zone=perserver:10m;
include mime.types;
include fastcgi.conf;
default_type application/octet-stream;
charset utf-8;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 64k;
sendfile on;
autoindex off;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 120;

fastcgi_connect_timeout 60;
fastcgi_send_timeout 60;
fastcgi_read_timeout 60;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_for';

client_max_body_size 10m;

include ../conf.d/*.conf;
}

注意:lua_load_resty_core off;如果不加会有以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nginx: [alert] detected a LuaJIT version which is not OpenResty's; many optimizations will be disabled and performance will be compromised (see https://github.com/openresty/luajit2 for OpenResty's LuaJIT or, even better, consider using the OpenResty releases from https://openresty.org/en/download.html)
nginx: [error] lua_load_resty_core failed to load the resty.core module from https://github.com/openresty/lua-resty-core; ensure you are using an OpenResty release from https://openresty.org/en/download.html (rc: 2, reason: module 'resty.core' not found:
no field package.preload['resty.core']
no file ' /usr/local/lib/lua-resty-core-0.1.17/lib/resty/core.lua'
no file './resty/core.lua'
no file '/usr/local/share/luajit-2.0.5/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core/init.lua'
no file './resty/core.so'
no file '/usr/local/lib/lua/5.1/resty/core.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './resty.so'
no file '/usr/local/lib/lua/5.1/resty.so'
no file '/usr/local/lib/lua/5.1/loadall.so')

创建放图片的目录

目录规划

  • /var/www 放网页,css,js等资源
  • /var/fielbase 放图片
  • /var/filebase/upload 上传的图片放这里
1
2
3
mkdir -p /var/filebase/upload 
mkdir -p /var/filebase/cache/thumb
chown -R nginx:nginx /var/filebase

配置站点配置文件

在/usr/local/tengine/conf.d目录下创建demo.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
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
# 定义lua缩略图支持的图片尺寸及开关
init_by_lua '
image_sizes_check = true
image_sizes = {"800x800", "400x400","200x200","100x100", "-800", "-400", "-200","-100", "800-", "400-", "200-","100-"}
';

server {
listen 80;
servername img.xyz.com;
index index.php index.html index.htm;

set $root_path '/var/www';
root $root_path;

# /lua仅用于测试,可去掉
location /lua {
default_type 'text/plain';
content_by_lua 'ngx.say("hello, ttlsa lua")';
}

# 这里也是需要根据实际情况修改的,这里的是用了rewrite
location / {
try_files $uri $uri/ /index.php?$args;

# add support for img which has query params,
# like: xxx.jpg?a=b&c=d_750x750.jpg
if ($args ~* "^([^_]+)_(d+)+x(d+)+.(jpg|jpeg|gif|png)$") {
set $w $2;
set $h $3;
set $img_ext $4;

# rewrite ^?(.*)$ _${w}x${h}.$img_ext? last;
rewrite ([^.]*).(jpg|jpeg|png|gif)$ $1.$2_${w}x${h}.$img_ext? permanent;
}
}

# set var for thumb pic
set $upload_path /var/filebase;
set $img_original_root $upload_path;# original root;
set $img_thumbnail_root $upload_path/cache/thumb;
set $img_file $img_thumbnail_root$uri;

# like:/xx/xx/xx.jpg_100-.jpg or /xx/xx/xx.jpg_-100.jpg
location ~* ^(.+.(jpg|jpeg|gif|png))_((d+-)|(-d+)).(jpg|jpeg|gif|png)$ {
root $img_thumbnail_root; # root path for croped img
set $img_size $3;

if (!-f $img_file) { # if file not exists
add_header X-Powered-By 'Nginx+Lua+GraphicsMagick By Botao'; # header for test
add_header file-path $request_filename; # header for test
set $request_filepath $img_original_root$1; # origin_img full path:/document_root/1.gif
set $img_size $3; # img width or height size depends on uri
set $img_ext $2; # file ext
content_by_lua_file /usr/local/nginx/lua/autoSize.lua; # load lua
}
}

# like: /xx/xx/xx.jpg_100x100.jpg
location ~* ^(.+.(jpg|jpeg|gif|png))_(d+)+x(d+)+.(jpg|jpeg|gif|png)$ {
root $img_thumbnail_root; # root path for croped img

if (!-f $img_file) { # if file not exists
add_header X-Powered-By 'Nginx+Lua+GraphicsMagick By Botao'; # header for test
add_header file-path $request_filename; # header for test
set $request_filepath $img_original_root$1; # origin_img file path
set $img_width $3; # img width
set $img_height $4; # height
set $img_ext $5; # file ext
content_by_lua_file /usr/local/nginx/lua/cropSize.lua; # load lua
}
}

# if need (all go there)
location ~* /upload {
root $img_original_root;
}


location ~ /.ht {
deny all;
}
}

lua脚本

  • /usr/local/tengine/lua/autoSize.lua
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

Lua Key

Lua学习笔记(5)table的长度