Skip to content

Repository files navigation

igp — Private Instagram Archive

Turn your Instagram data export into a private, self-hosted photo gallery on Cloudflare. Built with Astro and deployed as a Cloudflare Worker with R2 storage for media.

Features

  • Instagram-style grid — responsive thumbnail grid generated from your export
  • Post detail pages — full-size images, video playback, carousels, and captions
  • Role-based access — three tiers derived from your export's follower/close-friends lists:
    • Close friends — full access including pre-2020 posts and the archive page
    • Friends — access to posts from 2020 onward
    • Guests — see a "private archive" landing page only
  • No passwords — visitors log in with their Instagram username; access is granted based on your exported follower lists
  • Full archive page — all posts in one grid (close friends only)
  • Media served from R2 — full-size images and video load directly from a public R2 bucket (no Worker proxy)

Prerequisites

Requirement Notes
Node.js ≥ 22.12 (see package.jsonengines)
mise (recommended) From igp/, run mise install to install the pinned Node and Yarn versions
Yarn If you do not use mise, install Yarn per the official install guide (this repo uses Yarn 4; package.jsonpackageManager pins the version)
ffmpeg on PATH Required by yarn prep to extract video poster frames
Instagram data export Request a download from Instagram (Help Center: request export). Use the JSON format (not HTML), then unzip — see Where to put your Instagram export
Cloudflare account With an R2 bucket for media storage

Where to put your Instagram export

If you have not downloaded your data yet, start with Instagram’s instructions: Download a copy of your information.

All tooling assumes a fixed location: a directory named instagram sitting next to the igp project folder (sibling of igp/, not inside it).

Rule Detail
Folder name Must be exactly instagram (lowercase). Scripts resolve it as ../instagram from igp/.
Parent directory The parent of instagram/ must also be the parent of igp/. Same level on disk.
What goes inside The contents of Meta’s JSON export: you should have paths like instagram/media/posts/…, instagram/connections/followers_and_following/…, and instagram/your_instagram_activity/media/posts_1.json.

If Meta’s ZIP unpacks to a single dated folder (e.g. instagram-yourname-2024-01-01-…/), rename that folder to instagram and place it next to igp/, or move its contents into an instagram/ folder you create there. Do not add an extra nesting level so that media/ is missing under instagram/media/.

Example if this repository is checked out as ig-static/:

ig-static/                      ← repository root (parent of both folders)
├── instagram/                  ← YOUR EXPORT LIVES HERE (sibling of igp/)
│   ├── media/posts/
│   ├── connections/followers_and_following/
│   └── your_instagram_activity/media/posts_1.json
└── igp/                        ← this app (you run yarn commands from here)
    ├── package.json
    └── ...

The same layout applies under any root: …/instagram/ and …/igp/ must share the same …/ parent.

Quick Start

From the repository root, enter this project, install the toolchain, then dependencies. Put your export in ../instagram (see above) before yarn prep.

cd igp
mise install   # skip if you manage Node/Yarn yourself (see Prerequisites)
yarn install

# Local environment
cp .dev.vars.example .dev.vars
# Edit .dev.vars — set R2_PUBLIC_URL and AUTH_SECRET

# One-time (re-run after export changes)
yarn prep

yarn dev

Open localhost:4321 and log in with any username from your followers list.

Commands

Command Action
yarn prep Generate friends list, thumbnails, and verify assets (run once after export changes)
yarn dev Start local dev server at localhost:4321
yarn build Verify grid assets, then build to ./dist/
yarn preview Prep, build, and preview locally
yarn deploy Prep, build, and deploy to Cloudflare
yarn upload-media Upload media files to R2 (see Media Upload)

Deploying to Cloudflare

1. Create the R2 bucket

yarn exec wrangler r2 bucket create igp-media

Make the bucket publicly accessible (via R2 custom domain or r2.dev subdomain) and note the public URL.

2. Set secrets

yarn exec wrangler secret put AUTH_SECRET
# Enter a strong random string — used to sign session cookies

yarn exec wrangler secret put R2_PUBLIC_URL
# Enter your bucket's public URL (e.g. https://media.your-domain.com)

3. Upload media to R2

yarn upload-media --remote               # upload all media
yarn upload-media --remote --skip-existing  # only upload new files

4. Deploy

yarn deploy

Media Upload

The upload-media script reads files from ../instagram (same export location as above) and uploads them to R2 with keys matching the export paths (e.g. media/posts/202301/12345.jpg).

Flag Effect
--remote Upload to production R2 (default is local dev bucket)
--skip-existing Skip files that already exist in the bucket

Use POST_LIMIT=N to limit processing to the N most recent posts (applies to prep, build, and upload).

Environment Variables

Variable Where Purpose
AUTH_SECRET .dev.vars locally; in production use yarn exec wrangler secret put AUTH_SECRET Signs session cookies — any string, keep it secret
R2_PUBLIC_URL .dev.vars locally; in production use yarn exec wrangler secret put R2_PUBLIC_URL Public base URL for your R2 bucket
POST_LIMIT Shell env (optional) Limit to N most recent posts (useful for dev/testing)

How Authentication Works

There are no passwords. The login page asks for an Instagram username, which is checked against your exported follower and close-friends lists (generated into src/data/friends.json by yarn prep).

  • Usernames in your close friends list → close_friend role (full access)
  • Other followersfriend role (2020+ posts only)
  • guest or demoguest role (welcome page only)
  • Unknown usernames → rejected

Sessions are HMAC-signed cookies (30-day expiry).

About

hosted ig archive

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages