How to Use Varnish to Speed up my Website

Because Symfony's cache uses the standard HTTP cache headers, the HTTP Cache can be replaced with any other reverse proxy. Varnish is a powerful, open-source, HTTP accelerator capable of serving cached content fast and including support for Edge Side Includes.

Symfony のキャッシュは標準の HTTP キャッシュ ヘッダーを使用するため、HTTP キャッシュは他のリバース プロキシに置き換えることができます。 Varnish は強力なオープンソースの HTTP アクセラレーターであり、キャッシュされたコンテンツを高速に提供でき、Edge Side Includes のサポートを含みます。

Make Symfony Trust the Reverse Proxy

Varnish automatically forwards the IP as X-Forwarded-For and leaves the X-Forwarded-Proto header in the request. If you do not configure Varnish as trusted proxy, Symfony will see all requests as coming through insecure HTTP connections from the Varnish host instead of the real client.

Varnish は IP を X-Forwarded-For として自動的に転送し、X-Forwarded-Proto ヘッダーをリクエストに残します。 Varnish の信頼できるプロキシを構成しない場合、Symfony はすべてのリクエストを、実際のクライアントではなく、Varnish ホストからの安全でない HTTP 接続を経由して来るものとして認識します。

Remember to call the Request::setTrustedProxies() method in your front controller so that Varnish is seen as a trusted proxy and the X-Forwarded-* headers are used.

Varnish が信頼できるプロキシとして認識され、X-Forwarded-* ヘッダーが使用されるように、フロント コントローラーで Request::setTrustedProxies() メソッドを呼び出すことを忘れないでください。

Routing and X-FORWARDED Headers

To ensure that the Symfony Router generates URLs correctly with Varnish, an X-Forwarded-Port header must be present for Symfony to use the correct port number.

Symfony Router が Varnish で URL を正しく生成するようにするには、Symfony が正しいポート番号を使用できるように X-Forwarded-Port ヘッダーが存在する必要があります。

This port number corresponds to the port your setup is using to receive external connections (80 is the default value for HTTP connections). If the application also accepts HTTPS connections, there could be another proxy (as Varnish does not do HTTPS itself) on the default HTTPS port 443 that handles the SSL termination and forwards the requests as HTTP requests to Varnish with an X-Forwarded-Proto header. In this case, you need to add the following configuration snippet:

このポート番号は、セットアップが外部接続を受信するために使用しているポートに対応しています (HTTP 接続のデフォルト値は 80 です)。アプリケーションが HTTPS 接続も受け入れる場合、SSL ターミネーションを処理し、X-Forwarded-Protoheader を使用してリクエストを HTTP リクエストとして Varnish に転送する別のプロキシがデフォルトの HTTPS ポート 443 に存在する可能性があります (Varnish は HTTPS 自体を処理しないため)。この場合、次の構成スニペットを追加する必要があります。
1
2
3
4
5
6
7
sub vcl_recv {
    if (req.http.X-Forwarded-Proto == "https" ) {
        set req.http.X-Forwarded-Port = "443";
    } else {
        set req.http.X-Forwarded-Port = "80";
    }
}

Cookies and Caching

By default, most caching proxies do not cache anything when a request is sent with cookies or a basic authentication header. This is because the content of the page is supposed to depend on the cookie value or authentication header.

デフォルトでは、ほとんどのキャッシング プロキシは、Cookie または基本認証ヘッダーを使用してリクエストが送信された場合、何もキャッシュしません。これは、ページのコンテンツが Cookie 値または認証ヘッダーに依存することになっているためです。

If you know for sure that the backend never uses sessions or basic authentication, have Varnish remove the corresponding header from requests to prevent clients from bypassing the cache. In practice, you will need sessions at least for some parts of the site, e.g. when using forms with CSRF Protection. In this situation, make sure to only start a session when actually needed and clear the session when it is no longer needed. Alternatively, you can look into caching pages that contain CSRF protected forms.

バックエンドがセッションまたは基本認証を使用しないことが確実にわかっている場合は、クライアントがキャッシュをバイパスするのを防ぐために、対応するヘッダーをリクエストから削除してください。実際には、少なくともサイトの一部でセッションが必要になります。 CSRF 保護のあるフォームを使用する場合。この状況では、実際に必要なときにのみセッションを開始し、不要になったときにセッションをクリアするようにしてください。または、CSRF で保護されたフォームを含むキャッシュ ページを調べることもできます。

Cookies created in JavaScript and used only in the frontend, e.g. when using Google Analytics, are nonetheless sent to the server. These cookies are not relevant for the backend and should not affect the caching decision. Configure your Varnish cache to clean the cookies header. You want to keep the session cookie, if there is one, and get rid of all other cookies so that pages are cached if there is no active session. Unless you changed the default configuration of PHP, your session cookie has the name PHPSESSID:

JavaScript で作成され、フロントエンドでのみ使用される Cookie。 Google アナリティクスを使用している場合でも、サーバーに送信されます。これらの Cookie はバックエンドには関係なく、キャッシュの決定には影響しません。 Cookie ヘッダーを消去するように Varnish キャッシュを構成します。セッション Cookie がある場合は保持し、他のすべての Cookie を削除して、アクティブなセッションがない場合にページがキャッシュされるようにします。 PHP のデフォルト設定を変更しない限り、セッション Cookie の名前は PHPSESSID になります。
  • Varnish 4
    ワニス 4
  • Varnish 3
    ワニス 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sub vcl_recv {
    // Remove all cookies except the session ID.
    if (req.http.Cookie) {
        set req.http.Cookie = ";" + req.http.Cookie;
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID)=", "; \1=");
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

        if (req.http.Cookie == "") {
            // If there are no more cookies, remove the header to get the page cached.
            unset req.http.Cookie;
        }
    }
}

Tip

ヒント

If content is not different for every user, but depends on the roles of a user, a solution is to separate the cache per group. This pattern is implemented and explained by the FOSHttpCacheBundle under the name User Context.

コンテンツがユーザーごとに異なるのではなく、ユーザーの役割に依存する場合、解決策はグループごとにキャッシュを分離することです。このパターンは、FOSHttpCacheBundle によって nameUser コンテキストで実装および説明されます。

Ensure Consistent Caching Behavior

Varnish uses the cache headers sent by your application to determine how to cache content. However, versions prior to Varnish 4 did not respect Cache-Control: no-cache, no-store and private. To ensure consistent behavior, use the following configuration if you are still using Varnish 3:

Varnish は、アプリケーションから送信されたキャッシュ ヘッダーを使用して、コンテンツをキャッシュする方法を決定します。ただし、Varnish 4 より前のバージョンでは、Cache-Control: no-cache、no-store、および private が考慮されませんでした。 Varnish 3 をまだ使用している場合は、一貫した動作を確保するために、次の構成を使用します。
  • Varnish 3
    ワニス 3
1
2
3
4
5
6
7
8
9
10
sub vcl_fetch {
    // By default, Varnish3 ignores Cache-Control: no-cache and private
    // https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control
    if (beresp.http.Cache-Control ~ "private" ||
        beresp.http.Cache-Control ~ "no-cache" ||
        beresp.http.Cache-Control ~ "no-store"
    ) {
        return (hit_for_pass);
    }
}

Tip

ヒント

You can see the default behavior of Varnish in the form of a VCL file: default.vcl for Varnish 3, builtin.vcl for Varnish 4.

Varnish のデフォルトの動作は、VCL ファイルの形式で確認できます。Varnish 3 の場合は default.vcl、Varnish 4 の場合は builtin.vcl です。

Enable Edge Side Includes (ESI)

As explained in the Edge Side Includes article, Symfony detects whether it talks to a reverse proxy that understands ESI or not. When you use the Symfony reverse proxy, you don't need to do anything. But to make Varnish instead of Symfony resolve the ESI tags, you need some configuration in Varnish. Symfony uses the Surrogate-Capability header from the Edge Architecture described by Akamai.

エッジ サイド インクルードの記事で説明されているように、Symfony は、ESI を理解するリバース プロキシと通信するかどうかを検出します。 Symfony リバース プロキシを使用する場合、何もする必要はありません。ただし、Symfony の代わりに Varnish で ESI タグを解決するには、Varnish でいくつかの構成が必要です。 Symfony は、Akamai によって記述されたエッジ アーキテクチャの Surrogate-Capability ヘッダーを使用します。

Note

ノート

Varnish only supports the src attribute for ESI tags (onerror and alt attributes are ignored).

Varnish は ESI タグの src 属性のみをサポートします (onerror および alt 属性は無視されます)。

First, configure Varnish so that it advertises its ESI support by adding a Surrogate-Capability header to requests forwarded to the backend application:

まず、バックエンド アプリケーションに転送されるリクエストに Surrogate-Capability ヘッダーを追加して、ESI サポートをアドバタイズするように Varnish を構成します。
1
2
3
4
sub vcl_recv {
    // Add a Surrogate-Capability header to announce ESI support.
    set req.http.Surrogate-Capability = "abc=ESI/1.0";
}

Note

ノート

The abc part of the header isn't important unless you have multiple "surrogates" that need to advertise their capabilities. See Surrogate-Capability Header for details.

ヘッダーの abc 部分は、機能をアドバタイズする必要がある複数の「サロゲート」がない限り重要ではありません。詳細については、Surrogate-Capability ヘッダーを参照してください。

Then, optimize Varnish so that it only parses the response contents when there is at least one ESI tag by checking the Surrogate-Control header that Symfony adds automatically:

次に、Symfony が自動的に追加する Surrogate-Control ヘッダーをチェックして、少なくとも 1 つの ESI タグがある場合にのみ応答コンテンツを解析するように Varnish を最適化します。
  • Varnish 4
    ワニス 4
  • Varnish 3
    ワニス 3
1
2
3
4
5
6
7
sub vcl_backend_response {
    // Check for ESI acknowledgement and remove Surrogate-Control header
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi = true;
    }
}

Tip

ヒント

If you followed the advice about ensuring a consistent caching behavior, those VCL functions already exist. Append the code to the end of the function, they won't interfere with each other.

キャッシュ動作の一貫性を確保するためのアドバイスに従った場合、これらの VCL 関数は既に存在します。コードを関数の最後に追加すると、互いに干渉しなくなります。

Cache Invalidation

If you want to cache content that changes frequently and still serve the most recent version to users, you need to invalidate that content. While cache invalidation allows you to purge content from your proxy before it has expired, it adds complexity to your caching setup.

頻繁に変更されるコンテンツをキャッシュし、引き続き最新バージョンをユーザーに提供する場合は、そのコンテンツを無効にする必要があります。キャッシュの無効化により、有効期限が切れる前にプロキシからコンテンツを削除できますが、キャッシュ設定が複雑になります。

Tip

ヒント

The open source FOSHttpCacheBundle takes the pain out of cache invalidation by helping you to organize your caching and invalidation setup.

オープン ソースの FOSHttpCacheBundle は、キャッシュと無効化のセットアップを整理するのに役立つため、キャッシュの無効化に伴う問題を解決します。

The documentation of the FOSHttpCacheBundle explains how to configure Varnish and other reverse proxies for cache invalidation.

FOSHttpCacheBundle のドキュメントでは、Varnish やその他のリバース プロキシをキャッシュ無効化のために構成する方法について説明しています。