OpenGraphy is an original Go-based Open Graph / Twitter Card metadata checker, social preview renderer, diagnostics tool, and public preview gallery.
It is inspired by common social preview checker workflows, but it does not copy third-party logos, HTML, CSS, JavaScript, images, fonts, or trademarks.
- Server-side metadata fetching, closer to social crawler behavior than browser-side fetches.
- Open Graph and Twitter Card parsing.
- Facebook, X/Twitter, LinkedIn, WhatsApp, Discord, and Pinterest-style preview cards.
- Diagnostic score and repair suggestions.
- Redis 4-hour metadata cache.
- Anonymous online users, total visits, total checks, cache hit/miss stats.
- Public wall of qualified previews.
- PK voting: winner +1, loser -1, initial rating 1400.
- Leaderboard backed by Redis and synced to SQLite hourly.
- Multilingual UI with language cookie.
- Cookie consent banner and privacy page.
This workspace currently may not have Go installed locally. The intended development path is Docker:
docker network create proxy
docker compose up --buildThen open the service through the configured reverse proxy / Nginx container.
The app uses Tailwind CSS as a compiled enhancement layer on top of the existing semantic CSS. Production does not need Node: the generated file is committed at web/static/css/tailwind.css.
After changing web/assets/css/input.css or Tailwind config, rebuild CSS:
npm install
npm run build:cssWhen CSS changes, bump the query-string version in templates so /static long-cache clients receive the new file.
Copy .env.example to .env and set:
PUBLIC_BASE_URLRATE_SALTBOT_USER_AGENTADMIN_TOKENoptional; when set, enables/admin/gallery?token=...for private gallery maintenance.
og:metadata:{sha256(url)}: metadata cache, TTL 4 hours.og:work:{id}: qualified public preview work.og:works:recent: sorted set by latest seen timestamp.og:works:rating: sorted set by PK rating.stats:visits:totalstats:checks:totalstats:onlinestats:locale:{locale}stats:cache:hitsstats:cache:missesrl:s:{session}andrl:ip:{hash}: short-lived rate limits.
Gallery works are persisted in SQLite at SQLITE_PATH and hydrated back into Redis when the app starts. The app also syncs Redis gallery state into SQLite at startup and once per hour.
For browser-based maintenance, set ADMIN_TOKEN and open /admin/gallery?token=YOUR_TOKEN once. The app stores a short-lived HttpOnly admin cookie and redirects back to /admin/gallery.
Run maintenance commands inside the app container:
docker compose exec app /app/opengraphy gallery-health
docker compose exec app /app/opengraphy gallery-sync
docker compose exec app /app/opengraphy gallery-seedgallery-healthprints Redis recent count, SQLite works count, and the total used by stats.gallery-syncwrites works still present in Redis into SQLite immediately.gallery-seedinserts the built-in showcase previews only when both Redis and SQLite are empty.
- Submitted metadata check results are cached for 4 hours.
- Plain IP addresses are not stored.
- Rate limiting uses salted hashes with short TTL.
- Anonymous session cookies support presence and rate limiting.
- Gallery stores only qualified public website preview data: URL, final URL, title, description, preview image, score, rating, wins/losses.
- No third-party analytics or advertising cookies are included.
The fetcher:
- Allows only
httpandhttps. - Blocks localhost, loopback, private, link-local, multicast, and reserved networks.
- Resolves DNS before fetching.
- Re-validates redirect targets.
- Limits redirects to 5.
- Limits HTML response body to 2MB.
- Uses an 8 second timeout.
- Does not execute JavaScript.
Add translations in internal/i18n/i18n.go. Language choice uses:
langcookie.Accept-Language.- Fallback to English.
The compose file intentionally does not expose the app container directly to the host. Services communicate on an internal network and the external proxy network for reverse-proxy integration.
For opengraph.aston.tw:
- Point DNS
opengraph.aston.twto the server running the public reverse proxy. - Create or keep the shared Docker network:
docker network create proxy- Copy
.env.exampleto.envand set a strongRATE_SALT. - Start this app:
docker compose up -d --build- In the existing public reverse proxy, route
opengraph.aston.twto the Docker network alias:
server {
listen 80;
server_name opengraph.aston.tw;
location / {
proxy_pass http://opengraphy-web:80;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}If TLS is terminated at the public reverse proxy, issue the certificate there. This app's internal Nginx listens on port 80 only and stays behind the reverse proxy.
Validate compose changes with:
docker compose config