Caching strategy for a page that varies by IP
One approach could be to use a middleware to set a query parameter:

  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
    $ip = $request-&gt;getClientIp();
    if (Util::requestFromCampus($ip)) {
      $request-&gt;query-&gt;add(['oncampus' =&gt; '1']);
    }
    else {
      // remove the query parameter in case an off-campus user sets it incorrectly
      $request-&gt;query-&gt;remove('oncampus');  
    }
    return $this-&gt;httpKernel-&gt;handle($request, $type, $catch);
  }


Set a priority higher than 200, so that it runs before the page cache. The page cache uses the url including the query string as cache key and so both versions can be delivered from cache, which is good for performance.

As example how to set this up see Drupal\ban\BanMiddleware.

If you use this approach you don't need the custom cache context anymore, you can use a context for the query argument in content that varies for off- and on-campus users.