Skip to content

Zola/opengraphy

Repository files navigation

OpenGraphy

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.

Features

  • 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.

Local Development

This workspace currently may not have Go installed locally. The intended development path is Docker:

docker network create proxy
docker compose up --build

Then open the service through the configured reverse proxy / Nginx container.

Frontend CSS

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:css

When CSS changes, bump the query-string version in templates so /static long-cache clients receive the new file.

Environment

Copy .env.example to .env and set:

  • PUBLIC_BASE_URL
  • RATE_SALT
  • BOT_USER_AGENT
  • ADMIN_TOKEN optional; when set, enables /admin/gallery?token=... for private gallery maintenance.

Redis Keys

  • 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:total
  • stats:checks:total
  • stats:online
  • stats:locale:{locale}
  • stats:cache:hits
  • stats:cache:misses
  • rl:s:{session} and rl:ip:{hash}: short-lived rate limits.

Gallery Maintenance

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-seed
  • gallery-health prints Redis recent count, SQLite works count, and the total used by stats.
  • gallery-sync writes works still present in Redis into SQLite immediately.
  • gallery-seed inserts the built-in showcase previews only when both Redis and SQLite are empty.

Privacy Design

  • 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.

SSRF Protection

The fetcher:

  • Allows only http and https.
  • 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.

Adding Languages

Add translations in internal/i18n/i18n.go. Language choice uses:

  1. lang cookie.
  2. Accept-Language.
  3. Fallback to English.

Deployment Notes

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:

  1. Point DNS opengraph.aston.tw to the server running the public reverse proxy.
  2. Create or keep the shared Docker network:
docker network create proxy
  1. Copy .env.example to .env and set a strong RATE_SALT.
  2. Start this app:
docker compose up -d --build
  1. In the existing public reverse proxy, route opengraph.aston.tw to 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

About

Go Open Graph metadata checker, social preview gallery, and PK leaderboard

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors