Thank you for all the replies and suggestions. I’m going absolutely insane trying to troubleshoot this. I thought there might be an issue with Drupal or some PHP nonsense, so I set up a static HTML page with Twitter card metadata and I am close to throwing my computer out the window.
The Twitter Card validator does not show an image preview. Here is the verbose output:
INFO: Page fetched successfully
INFO: 12 metatags were found
INFO: twitter:card = summary_large_image tag found
INFO: Card loaded successfully
There is no CDN or cache in front of our server, and I see Twitterbot/1.0 successfully request the page and then the image specified in the card metadata:
199.16.157.181 - - [28/Apr/2021:14:06:21 +0100] "GET /twitter-test/ HTTP/1.1" 200 7610 "-" "Twitterbot/1.0"
199.16.157.182 - - [28/Apr/2021:14:06:21 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 215821 "-" "Twitterbot/1.0"
199.16.157.180 - - [28/Apr/2021:14:06:21 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 215821 "-" "Twitterbot/1.0"
199.16.157.181 - - [28/Apr/2021:14:06:21 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 215821 "-" "Twitterbot/1.0"
199.16.157.183 - - [28/Apr/2021:14:06:21 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 215821 "-" "Twitterbot/1.0"
199.16.157.182 - - [28/Apr/2021:14:06:22 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 215821 "-" "Twitterbot/1.0"
Several different Twitterbot instances request this image, though the size is not correct (by an order of magnitude!). The content length in the requests above is 215821, but the size of the image on disk is 1860045. If I request the image with curl, wget, or Firefox the content length is still wrong, but only by a few bytes:
182.113.175.160 - - [28/Apr/2021:14:33:43 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 1867195 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"
182.113.175.160 - - [28/Apr/2021:14:34:03 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 1866631 "-" "curl/7.76.1"
182.113.175.160 - - [28/Apr/2021:14:34:22 +0100] "GET /twitter-test/DSC_0488.JPG HTTP/1.1" 200 1867375 "-" "Wget/1.21.1"
I made a second static HTML page to test. This one is exactly the same as the first one, except the Twitter card image URL points to the same image on another server:
Now the Twitter Card validator shows the image! Here is the validator status:
INFO: Page fetched successfully
INFO: 12 metatags were found
INFO: twitter:card = summary_large_image tag found
INFO: Card loaded successfully
The logs on my other server show:
199.16.157.183 - - [28/Apr/2021:15:41:18 +0200] "GET /2020/04/gadaras-octagonal-martyrium/DSC_0488.JPG HTTP/1.1" 200 1860045 "-" "Twitterbot/1.0"
The content length of the response here is correct! What the hell is going on? The first server is Apache HTTPD and it returns the correct image size for Firefox, curl, and wget, but not for Twitterbot. The second server is nginx and the file is served straight from the disk with try_files. Is this some bizarre Apache configuration issue?