最近の砂場活動その8: Nginxとrendertronでprerenderingされた結果をクローラに見せる

趣味サイトをVue.jsを使ってSPAとして作っている。人間が見る分には問題ないが、GoogleBotがきたときにレンダリングされていなくて解釈された結果が悲しい感じになっている。

Vue.jsでもサーバーサイドレンダリングができたりするようだが、アプリケーションサーバーはnodeではなくGolangで書いている。そのため、導入が面倒そう。仕方ないので諦めていたが、レンダリングされた結果を返してくれるHTTPサーバーとして振るまってくれるrendertronというものがあるそうだ。Headless Chromeを中で使っている様子。なるほど、こういう使い方ができるのか。

早速導入してみた。nginxでこういう感じで場合分けさせる。

  • 人間がきた場合: nginx(port: 7777) => アプリサーバー(port: 7778)
  • Botがきた場合: nginx(port: 7777) => rendertron(port: 3000) => アプリサーバー(port: 7778)

設定ファイルはこんな感じ。nginx初心者なので、書き方があんまりよくないかもしれない...。

upstream local-backend {
    server localhost:7778;
}

upstream local-rendertron {
    server localhost:3000;
}

server {
    listen 7777 default_server;
    set $prerender 0;
        if ($http_user_agent ~* "googlebot") { # 他にも追加したい場合にはいい感じに正規表現を書く
        set $prerender 1;
    }

    location / {
        if ($prerender = 1) {
            rewrite ^(.*)$ /render/https://www.machine-learning.news$1 break;
            proxy_pass http://local-rendertron;
        }
        root /www/app;
        proxy_set_header Host $http_host;
        expires 1d;
        gzip on;
        gzip_types text/css application/javascript;
    }
    location /api {
        proxy_pass http://local-backend;
        gzip on;
        gzip_types application/json;
    }
}

nginxもアプリサーバーもrendertronもコンテナ使って動かしていて、ECSの1つのタスクの中に同居している。CloudFormationでの設定例はこんな感じ。

  ServerTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: 'go-active-learning'
      Cpu: 256
      Memory: 2048
      NetworkMode: awsvpc
      ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole"
      RequiresCompatibilities:
        - FARGATE
      ContainerDefinitions:
        - Name: "go-active-learning-app"
          PortMappings:
            - ContainerPort: 7778
          Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/go-active-learning:latest"
          EntryPoint:
            - "/app/go-active-learning.bin"
            - "serve"
          Essential: "true"
        - Name: "go-active-learning-nginx"
          PortMappings:
            - ContainerPort: 7777
          Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/go-active-learning-nginx:latest"
          Essential: "true"
        - Name: "rendertron"
          Image: "nkonev/rendertron-docker:latest"
          PortMappings:
            - ContainerPort: 3000
          Essential: "true"

これでGoogleBotもいい感じに解釈してくれるようになった。

問題点

トップページはGoogleBotもレンダリングされた結果を解釈してくれるようになってめでたいが、トップページ以外はVue.jsのルーティングがうまく動くようにまだ書けていない。いい感じにする方法があれば教えてください...。

参考