阿里云
阿里云多端小程序中小企业获客首选
发表主题 回复主题
  • 6459阅读
  • 4回复

[解决方案]Varnish 4.1 & WordPress 带来内存级加速

级别: 论坛版主
发帖
9349
云币
14165
— 本帖被 鬼才神兵 设置为精华(2016-08-01) —
b0_Ih6  
前言 o@&d d NO  
7FiQTS B:  
Varnish 是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang 使用3台 Varnish 代替了原来的 12 台 Squid,性能比以前更好。(超级老的梗了,但是就这么用吧。) Q{0!N8']"  
Cg! ]x o  
AGdFJ>/  
Varnish 和 WordPress 搭配是比较经典的组合了,目前解决方案也非常的多,可以完美兼容 WordPress,灰常的耐撕啊。目前很多教程主要都是 Varnish 3.x 的,但是目前 Varnish 4.1 了,因为规则有变化(子版本号一般来说规则不变,大版本号肯定是变得),所以就写个教程吧。 cKKl\g@}  
oHbG-p  
安装 +=/FKzT<  
/=bg(?nX  
RHEL /CentOS 7 安装: (haYY]W\  
  1. yum install epel-release
  2. rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.1.el7.rpm
  3. yum install varnish
PnKgUJoa0  
v iJK%^U=-  
Debian 8 安装: dlx "L%  
  1. apt-get install apt-transport-https
  2. curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -
  3. echo "deb https://repo.varnish-cache.org/debian/ jessie varnish-4.1"\
  4.     >> /etc/apt/sources.list.d/varnish-cache.list
  5. apt-get update
  6. apt-get install varnish
Iw<: k  
_K?{DnTb  
更多系统的安装请看: 5k^UZw  
https://www.varnish-cache.org/releases/index.html /b)V=mcR  
-$[o:dLO  
配置规则 zNs8yMnFr  
J}9 I5O  
修改 Nginx / Apache 端口 #0WGSIht<  
n!r<\4I  
首先,如果我们要让用户在 Http (80)端口访问的就是 Varnish 的缓存效果的话,肯定是得把 80 端口让出来的。所以我们需要修改我们的 Web 服务软件的端口,这里以 Nginx 为例(Apache 我有空写)。 Q3$AL@".  
&z@~n  
XRMYR97  
在 conf 目录里找相关配置文件,一般来说 nginx.conf 和 vhost/*.conf 文件里都是配置信息,不同安装方式、面板不同。然后就会看到有 lisen 80 意思就是监听 80 端口,我们这里改成 lisen 8080 就变成监听 8080 端口了,你可以试试在浏览器里访问以下例如:http://www.mf8.biz:8080 这样的,如果不能访问的话,就检查一下服务器的防火墙是否有开放 8080 端口。阿里、腾讯云、AWS 这样的云还有安全策略这样的功能,可能端口被禁也是这里。(其实外网能不能访问,问题也不大,内网可以就好。。。。。) csPziH$wl  
v^=Po6S[{+  
Vk/!_)  
记得重启 Nginx。
  1. service nginx restart
?J<V-,i  
(Mk9##R#  
缓存规则 .^fVm  
7ktSj}7W]  
因为 Varnish 已经跨了个版本了,所以就得规则已经不适宜新的版本了,所以你网上找到的至少是国内博客分享的教程可能都已经不能用了。这里贴一个。 规则不是唯一的,大家可以寻找更好的,也可以学习着己配置、完善。 ya<nD'%9  
9Dq^x&z(  
b=5"*=T{+  
修改 /etc/varnish/default.vcl 或者在 /etc/varnish/ 目录下添加一个 VCl 文件。 nNCG*Vu  
&.zG?e.  
!&$uq|-  
  1. vcl 4.0;
  2. # Based on: https://github.com/mattiasgeniar/varnish-4.0-configuration-templates/blob/master/default.vcl
  3. import std;
  4. import directors;
  5. backend server1 { # Define one backend
  6.   .host = "127.0.0.1";    # IP or Hostname of backend
  7.   .port = "80";           # Port Apache or whatever is listening
  8.   .max_connections = 300; # That's it
  9.   .probe = {
  10.     #.url = "/"; # short easy way (GET /)
  11.     # We prefer to only do a HEAD /
  12.     .request =
  13.       "HEAD / HTTP/1.1"
  14.       "Host: localhost"
  15.       "Connection: close"
  16.       "User-Agent: Varnish Health Probe";
  17.     .interval  = 5s; # check the health of each backend every 5 seconds
  18.     .timeout   = 1s; # timing out after 1 second.
  19.     .window    = 5;  # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick
  20.     .threshold = 3;
  21.   }
  22.   .first_byte_timeout     = 300s;   # How long to wait before we receive a first byte from our backend?
  23.   .connect_timeout        = 5s;     # How long to wait for a backend connection?
  24.   .between_bytes_timeout  = 2s;     # How long to wait between bytes received from our backend?
  25. }
  26. acl purge {
  27.   # ACL we'll use later to allow purges
  28.   "localhost";
  29.   "127.0.0.1";
  30.   "::1";
  31. }
  32. /*
  33. acl editors {
  34.   # ACL to honor the "Cache-Control: no-cache" header to force a refresh but only from selected IPs
  35.   "localhost";
  36.   "127.0.0.1";
  37.   "::1";
  38. }
  39. */
  40. sub vcl_init {
  41.   # Called when VCL is loaded, before any requests pass through it.
  42.   # Typically used to initialize VMODs.
  43.   new vdir = directors.round_robin();
  44.   vdir.add_backend(server1);
  45.   # vdir.add_backend(server...);
  46.   # vdir.add_backend(servern);
  47. }
  48. sub vcl_recv {
  49.   # Called at the beginning of a request, after the complete request has been received and parsed.
  50.   # Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable,
  51.   # which backend to use.
  52.   # also used to modify the request
  53.   set req.backend_hint = vdir.backend(); # send all traffic to the vdir director
  54.   # Normalize the header, remove the port (in case you're testing this on various TCP ports)
  55.   set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
  56.   # Normalize the query arguments
  57.   set req.url = std.querysort(req.url);
  58.   # Allow purging
  59.   if (req.method == "PURGE") {
  60.     if (!client.ip ~ purge) { # purge is the ACL defined at the begining
  61.       # Not from an allowed IP? Then die with an error.
  62.       return (synth(405, "This IP is not allowed to send PURGE requests."));
  63.     }
  64.     # If you got this stage (and didn't error out above), purge the cached result
  65.     return (purge);
  66.   }
  67.   # Only deal with "normal" types
  68.   if (req.method != "GET" &&
  69.       req.method != "HEAD" &&
  70.       req.method != "PUT" &&
  71.       req.method != "POST" &&
  72.       req.method != "TRACE" &&
  73.       req.method != "OPTIONS" &&
  74.       req.method != "PATCH" &&
  75.       req.method != "DELETE") {
  76.     /* Non-RFC2616 or CONNECT which is weird. */
  77.     return (pipe);
  78.   }
  79.   # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
  80.   if (req.http.Upgrade ~ "(?i)websocket") {
  81.     return (pipe);
  82.   }
  83.   # Only cache GET or HEAD requests. This makes sure the POST requests are always passed.
  84.   if (req.method != "GET" && req.method != "HEAD") {
  85.     return (pass);
  86.   }
  87.   # Some generic URL manipulation, useful for all templates that follow
  88.   # First remove the Google Analytics added parameters, useless for our backend
  89.   if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
  90.     set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
  91.     set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
  92.     set req.url = regsub(req.url, "\?&", "?");
  93.     set req.url = regsub(req.url, "\?$", "");
  94.   }
  95.   # Strip hash, server doesn't need it.
  96.   if (req.url ~ "\#") {
  97.     set req.url = regsub(req.url, "\#.*$", "");
  98.   }
  99.   # Strip a trailing ? if it exists
  100.   if (req.url ~ "\?$") {
  101.     set req.url = regsub(req.url, "\?$", "");
  102.   }
  103.   # Some generic cookie manipulation, useful for all templates that follow
  104.   # Remove the "has_js" cookie
  105.   set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
  106.   # Remove any Google Analytics based cookies
  107.   set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");
  108.   set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", "");
  109.   set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?", "");
  110.   set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", "");
  111.   set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
  112.   set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");
  113.   # Remove DoubleClick offensive cookies
  114.   set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
  115.   # Remove the Quant Capital cookies (added by some plugin, all __qca)
  116.   set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
  117.   # Remove the AddThis cookies
  118.   set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
  119.   # Remove a ";" prefix in the cookie if present
  120.   set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
  121.   # Are there cookies left with only spaces or that are empty?
  122.   if (req.http.cookie ~ "^\s*$") {
  123.     unset req.http.cookie;
  124.   }
  125.   if (req.http.Cache-Control ~ "(?i)no-cache") {
  126.   #if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ editors) { # create the acl editors if you want to restrict the Ctrl-F5
  127.   # http://varnish.projects.linpro.no/wiki/VCLExampleEnableForceRefresh
  128.   # Ignore requests via proxy caches and badly behaved crawlers
  129.   # like msnbot that send no-cache with every request.
  130.     if (! (req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) {
  131.       #set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache
  132.       return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops
  133.     }
  134.   }
  135.   # Large static files are delivered directly to the end-user without
  136.   # waiting for Varnish to fully read the file first.
  137.   # Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response()
  138.   if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
  139.     unset req.http.Cookie;
  140.     return (hash);
  141.   }
  142.   # Remove all cookies for static files
  143.   # A valid discussion could be held on this line: do you really need to cache static files that don't cause load? Only if you have memory left.
  144.   # Sure, there's disk I/O, but chances are your OS will already have these files in their buffers (thus memory).
  145.   # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
  146.   if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
  147.     unset req.http.Cookie;
  148.     return (hash);
  149.   }
  150.   # Send Surrogate-Capability headers to announce ESI support to backend
  151.   set req.http.Surrogate-Capability = "key=ESI/1.0";
  152.   if (req.http.Authorization) {
  153.     # Not cacheable by default
  154.     return (pass);
  155.   }
  156.   return (hash);
  157. }
  158. sub vcl_pipe {
  159.   # Called upon entering pipe mode.
  160.   # In this mode, the request is passed on to the backend, and any further data from both the client
  161.   # and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
  162.   # degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
  163.   # no other VCL subroutine will ever get called after vcl_pipe.
  164.   # Note that only the first request to the backend will have
  165.   # X-Forwarded-For set.  If you use X-Forwarded-For and want to
  166.   # have it set for all requests, make sure to have:
  167.   # set bereq.http.connection = "close";
  168.   # here.  It is not set by default as it might break some broken web
  169.   # applications, like IIS with NTLM authentication.
  170.   # set bereq.http.Connection = "Close";
  171.   # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
  172.   if (req.http.upgrade) {
  173.     set bereq.http.upgrade = req.http.upgrade;
  174.   }
  175.   return (pipe);
  176. }
  177. sub vcl_pass {
  178.   # Called upon entering pass mode. In this mode, the request is passed on to the backend, and the
  179.   # backend's response is passed on to the client, but is not entered into the cache. Subsequent
  180.   # requests submitted over the same client connection are handled normally.
  181.   # return (pass);
  182. }
  183. # The data on which the hashing will take place
  184. sub vcl_hash {
  185.   # Called after vcl_recv to create a hash value for the request. This is used as a key
  186.   # to look up the object in Varnish.
  187.   hash_data(req.url);
  188.   if (req.http.host) {
  189.     hash_data(req.http.host);
  190.   } else {
  191.     hash_data(server.ip);
  192.   }
  193.   # hash cookies for requests that have them
  194.   if (req.http.Cookie) {
  195.     hash_data(req.http.Cookie);
  196.   }
  197. }
  198. sub vcl_hit {
  199.   # Called when a cache lookup is successful.
  200.   if (obj.ttl >= 0s) {
  201.     # A pure unadultered hit, deliver it
  202.     return (deliver);
  203.   }
  204.   # https://www.varnish-cache.org/docs/trunk/users-guide/vcl-grace.html
  205.   # When several clients are requesting the same page Varnish will send one request to the backend and place the others on hold while fetching one copy from the backend. In some products this is called request coalescing and Varnish does this automatically.
  206.   # If you are serving thousands of hits per second the queue of waiting requests can get huge. There are two potential problems - one is a thundering herd problem - suddenly releasing a thousand threads to serve content might send the load sky high. Secondly - nobody likes to wait. To deal with this we can instruct Varnish to keep the objects in cache beyond their TTL and to serve the waiting requests somewhat stale content.
  207. # if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
  208. #   return (deliver);
  209. # } else {
  210. #   return (fetch);
  211. # }
  212.   # We have no fresh fish. Lets look at the stale ones.
  213.   if (std.healthy(req.backend_hint)) {
  214.     # Backend is healthy. Limit age to 10s.
  215.     if (obj.ttl + 10s > 0s) {
  216.       #set req.http.grace = "normal(limited)";
  217.       return (deliver);
  218.     } else {
  219.       # No candidate for grace. Fetch a fresh object.
  220.       return(fetch);
  221.     }
  222.   } else {
  223.     # backend is sick - use full grace
  224.       if (obj.ttl + obj.grace > 0s) {
  225.       #set req.http.grace = "full";
  226.       return (deliver);
  227.     } else {
  228.       # no graced object.
  229.       return (fetch);
  230.     }
  231.   }
  232.   # fetch & deliver once we get the result
  233.   return (fetch); # Dead code, keep as a safeguard
  234. }
  235. sub vcl_miss {
  236.   # Called after a cache lookup if the requested document was not found in the cache. Its purpose
  237.   # is to decide whether or not to attempt to retrieve the document from the backend, and which
  238.   # backend to use.
  239.   return (fetch);
  240. }
  241. # Handle the HTTP request coming from our backend
  242. sub vcl_backend_response {
  243.   # Called after the response headers has been successfully retrieved from the backend.
  244.   # Pause ESI request and remove Surrogate-Control header
  245.   if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
  246.     unset beresp.http.Surrogate-Control;
  247.     set beresp.do_esi = true;
  248.   }
  249.   # Enable cache for all static files
  250.   # The same argument as the static caches from above: monitor your cache size, if you get data nuked out of it, consider giving up the static file cache.
  251.   # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
  252.   if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
  253.     unset beresp.http.set-cookie;
  254.   }
  255.   # Large static files are delivered directly to the end-user without
  256.   # waiting for Varnish to fully read the file first.
  257.   # Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
  258.   if (bereq.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
  259.     unset beresp.http.set-cookie;
  260.     set beresp.do_stream = true;  # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
  261.     set beresp.do_gzip   = false;   # Don't try to compress it for storage
  262.   }
  263.   # Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along.
  264.   # This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box.
  265.   # A redirect can then often redirect the end-user to a URL on :8080, where it should be :80.
  266.   # This may need finetuning on your setup.
  267.   #
  268.   # To prevent accidental replace, we only filter the 301/302 redirects for now.
  269.   if (beresp.status == 301 || beresp.status == 302) {
  270.     set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", "");
  271.   }
  272.   # Set 2min cache if unset for static files
  273.   if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
  274.     set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
  275.     set beresp.uncacheable = true;
  276.     return (deliver);
  277.   }
  278.   # Don't cache 50x responses
  279.   if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
  280.     return (abandon);
  281.   }
  282.   # Allow stale content, in case the backend goes down.
  283.   # make Varnish keep all objects for 6 hours beyond their TTL
  284.   set beresp.grace = 6h;
  285.   return (deliver);
  286. }
  287. # The routine when we deliver the HTTP request to the user
  288. # Last chance to modify headers that are sent to the client
  289. sub vcl_deliver {
  290.   # Called before a cached object is delivered to the client.
  291.   if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
  292.     set resp.http.X-Cache = "HIT";
  293.   } else {
  294.     set resp.http.X-Cache = "MISS";
  295.   }
  296.   # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
  297.   # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
  298.   # So take hits with a grain of salt
  299.   set resp.http.X-Cache-Hits = obj.hits;
  300.   # Remove some headers: PHP version
  301.   unset resp.http.X-Powered-By;
  302.   # Remove some headers: Apache version & OS
  303.   unset resp.http.Server;
  304.   unset resp.http.X-Drupal-Cache;
  305.   unset resp.http.X-Varnish;
  306.   unset resp.http.Via;
  307.   unset resp.http.Link;
  308.   unset resp.http.X-Generator;
  309.   return (deliver);
  310. }
  311. sub vcl_purge {
  312.   # Only handle actual PURGE HTTP methods, everything else is discarded
  313.   if (req.method != "PURGE") {
  314.     # restart request
  315.     set req.http.X-Purge = "Yes";
  316.     return(restart);
  317.   }
  318. }
  319. sub vcl_synth {
  320.   if (resp.status == 720) {
  321.     # We use this special error status 720 to force redirects with 301 (permanent) redirects
  322.     # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
  323.     set resp.http.Location = resp.reason;
  324.     set resp.status = 301;
  325.     return (deliver);
  326.   } elseif (resp.status == 721) {
  327.     # And we use error status 721 to force redirects with a 302 (temporary) redirect
  328.     # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
  329.     set resp.http.Location = resp.reason;
  330.     set resp.status = 302;
  331.     return (deliver);
  332.   }
  333.   return (deliver);
  334. }
  335. sub vcl_fini {
  336.   # Called when VCL is discarded only after all requests have exited the VCL.
  337.   # Typically used to clean up VMODs.
  338.   return (ok);
  339. }
5cv&`h8uo_  
LRJY63A  
m5wfQ_}}ss  
3KyIBrdi?  
修改 Varnish 端口 p f\ Ybbs  
VO (KQx  
H%LoI)w  
Varnish 的默认端口是 6081,而不是 80 端口。所以还得改改。修改 /etc/default/varnish 文件。 _M;n.?H  
"Cj {Z@n  
" vW4"R6  
修改 -a :6081 \ ,改为 -a :80 \ 就可以监听 80 端口了,当然,前提是没有东西占用你的 80 端口。 y@#JzfY?Hr  
然后重启 varnish。
  1. service varnish restart
 b6`_;Z  
Xjy5Yj  
安装清理缓存的插件 fEdp^oVg  
  1. DAEMON_OPTS="-a :6081 \
  2.              -T localhost:6082 \
  3.              -f /etc/varnish/default.vcl \
  4.              -S /etc/varnish/secret \
  5.              -s malloc,256m -t 120"
Ihd{ @6m  
N)kZ2|oD  
因为缓存一直存着吧,你的内容就不变动了,所以,我们还需要 WordPress 的插件配合。目前的话,主流的缓存插件 WP Super cache,W3tc 之流都是有相关配合 Varnish 的功能的,但是目前公认最能配合 Varnish 的插件是:Varnish HTTP Purge。 很多洋鬼子也是建议就算你有 w3tc 这样的插件了,最好还是额外安装 Varnish HTTP Purge 插件。 t",=]k  
sew0n`d1  
!mjrI "_  
原创文章转载请注明:转载自:https://www.mf8.biz/varnish-wordpress-make-fast-1/
本帖最近评分记录: 2 条评分 云币 +11
宝商科技 云币 +1 varnish 与 WordPress 是绝佳组合 2016-08-15
鬼才神兵 云币 +10 不顶不舒服斯基 2016-08-01
级别: 论坛版主
发帖
1784
云币
3327

只看该作者 沙发  发表于: 2016-08-01
不顶不舒服斯基
级别: 攻城狮
发帖
612
云币
3100
只看该作者 板凳  发表于: 2016-08-07
看看
级别: 论坛版主
发帖
1030
云币
855
只看该作者 地板  发表于: 2016-08-15
varnish 与 WordPress 是绝佳组合
级别: 攻城狮
发帖
612
云币
3100
只看该作者 4楼 发表于: 2016-08-22
学习
发表主题 回复主题
« 返回列表上一主题下一主题

限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
验证问题: 22 - 19 = ?
上一个 下一个
      ×
      全新阿里云开发者社区, 去探索开发者的新世界吧!
      一站式的体验,更多的精彩!
      通过下面领域大门,一起探索新的技术世界吧~ (点击图标进入)