fanfiction.lol is an AO3 fork for fanfiction, original fiction, multimedia fanworks, and more. we're fandom/discourse agnostic and interested in people being creative. write whatever the hell you want here.
  • Ruby 56.6%
  • Gherkin 19.8%
  • HTML 15.6%
  • JavaScript 5.6%
  • CSS 2.1%
  • Other 0.3%
Find a file
Brennan Kenneth Brown bf82cdeb63
Some checks are pending
Automated Tests / rspec --exclude-pattern 'spec/{controllers,models}/**/*.rb' (push) Waiting to run
Automated Tests / rake db:otwseed (push) Waiting to run
Automated Tests / cucumber features/admins (push) Waiting to run
Automated Tests / cucumber features/bookmarks (push) Waiting to run
Automated Tests / cucumber features/collections (push) Waiting to run
Automated Tests / cucumber features/comments_and_kudos (push) Waiting to run
Automated Tests / cucumber features/gift_exchanges (push) Waiting to run
Automated Tests / cucumber features/importing (push) Waiting to run
Automated Tests / cucumber features/other_a (push) Waiting to run
Automated Tests / cucumber features/other_b (push) Waiting to run
Automated Tests / cucumber features/prompt_memes_a (push) Waiting to run
Automated Tests / cucumber features/prompt_memes_b (push) Waiting to run
Automated Tests / cucumber features/prompt_memes_c (push) Waiting to run
Automated Tests / cucumber features/search (push) Waiting to run
Automated Tests / cucumber features/tag_sets (push) Waiting to run
Automated Tests / cucumber features/tags_and_wrangling (push) Waiting to run
Automated Tests / cucumber features/users (push) Waiting to run
Automated Tests / cucumber features/works (push) Waiting to run
Automated Tests / rspec spec/controllers (push) Waiting to run
Automated Tests / rspec spec/models (push) Waiting to run
Brakeman Scan / Brakeman Scan (push) Waiting to run
Remove redundant 'Cartoons & Comics & Graphic Novels' media category
2026-05-31 03:54:13 -06:00
.git-rewrite Initial commit: fanfiction.lol archive 2026-05-31 02:34:56 -06:00
.github AO3-7475 Stop using cache-apt-pkgs-action in automated tests (#5830) 2026-05-23 10:48:29 +02:00
app Update search indexing and query cleaning 2026-05-31 02:30:10 -06:00
bin Add Docker deployment infrastructure and scripts 2026-05-29 00:44:12 -06:00
config Add Friends navigation menu and dropdown 2026-05-31 02:29:24 -06:00
db AO3-6978 Create and fill new table for import urls (#5795) 2026-05-10 20:31:28 -04:00
entrypoints Add Docker deployment infrastructure and scripts 2026-05-29 00:44:12 -06:00
factories AO3-6983 Add support form notices (#5389) 2026-02-03 18:57:36 +01:00
features Update feature tests for tags and work import 2026-05-31 02:30:16 -06:00
lib Update tasks and scripts for tag management 2026-05-31 02:30:20 -06:00
log Gitkeep the log dir 2011-02-09 16:33:41 -06:00
public Add deployment and backup scripts for cafe server 2026-05-31 02:33:15 -06:00
rubocop AO3-6732 Add custom cop for calling html_safe on translated strings (#4890) 2024-08-16 12:58:48 -04:00
script Remove redundant 'Cartoons & Comics & Graphic Novels' media category 2026-05-31 03:54:13 -06:00
scripts Add deployment and backup scripts for cafe server 2026-05-31 02:33:15 -06:00
spec Update specs for API helper and after tasks 2026-05-31 02:30:25 -06:00
test Set canonical: true by default for new tags 2026-05-31 02:29:19 -06:00
.codeclimate.yml AO3-6097 Remove Dewplayer from repo (#4427) 2023-04-19 19:40:33 -04:00
.codecov.yml AO3-5195 Use Codecov for coverage (#3093) 2017-10-02 23:16:52 -04:00
.devcontainer.json AO3-6916 Add devcontainer configuration (#5587) 2026-03-06 17:24:58 +01:00
.env.example Add Docker deployment infrastructure and scripts 2026-05-29 00:44:12 -06:00
.erb-lint.yml AO3-6913 AO3-6597 Allow queue to send invitations every N hours (#5091) 2025-04-06 11:46:09 -07:00
.gitattributes AO3-6804 Fix flaky tag wrangling fandoms test (#4909) 2024-09-01 16:36:47 -07:00
.gitignore Add docs/ to .gitignore 2026-05-31 02:54:07 -06:00
.hound.yml AO3-6605 Add Reviewdog for Rubocop check (#4631) 2023-11-12 21:59:48 -05:00
.jshintignore AO3-6097 Remove Dewplayer from repo (#4427) 2023-04-19 19:40:33 -04:00
.jshintrc AO3-5772 Exclude third party or minified JS files from checks (#3685) 2019-11-09 01:07:48 -05:00
.phrase.yml Update Phrase project ID (#5682) 2026-04-01 22:16:32 +02:00
.rubocop.yml AO3-6918 Implement 2fa for admins via TOTP (#5256) 2026-01-26 19:38:34 +00:00
.ruby-version AO3-7145 update ruby to 3.4 (#5375) 2025-10-02 19:30:59 +02:00
.simplecov AO3-6485 Switch to Codecov GitHub Action (#4458) 2023-02-21 23:57:16 -05:00
ACKNOWLEDGMENTS.md AO3-6133 Remove codeship from acknowledgments (#5405) 2025-10-11 12:12:10 -07:00
cafe-server-notes.md Add deployment and backup scripts for cafe server 2026-05-31 02:33:15 -06:00
Capfile rake deploy:all_interactive 2010-10-25 19:25:43 +00:00
config.ru AO3-6651 Update config to Rails 6.1 (#4690) 2024-01-27 18:48:38 +00:00
CONTRIBUTING.md Update CONTRIBUTING.md (#5759) 2026-04-26 15:02:35 -04:00
docker-compose.yml Move SMTP config to .env 2026-05-29 00:56:47 -06:00
fflol-logo-white.png Add branding assets and favicons 2026-05-31 02:29:29 -06:00
fflol-logo.png Add branding assets and favicons 2026-05-31 02:29:29 -06:00
Gemfile AO3-6454 AO3-6198 Remove Akismetor and handle Akismet API calls ourselves (#5809) 2026-05-16 12:11:55 +02:00
Gemfile.lock AO3-6454 AO3-6198 Remove Akismetor and handle Akismet API calls ourselves (#5809) 2026-05-16 12:11:55 +02:00
LICENSE AO3-5055 Add GNU GPL version 2 license (#2949) 2017-09-23 17:45:21 -04:00
Rakefile AO3-5195 Use Codecov for coverage (#3093) 2017-10-02 23:16:52 -04:00
README.md Revamp README with fork specifics and technical details 2026-05-31 02:49:52 -06:00
SECURITY.md AO3-6838 Update the TOS and TOS FAQ text, structure, and references (#4957) 2024-11-19 02:08:03 -05:00

fanfiction.lol

An independent fanfiction archive forked from the OTW-Archive codebase, the open-source software powering Archive of Our Own.

Live site: fanfiction.lol
Source code: source.tube/brennan/fanfiction.lol

What Makes This Fork Different?

No Invite Queue

Unlike AO3 (where 144,000+ people wait for invitations), anyone can register immediately. Sign up and start posting.

Fandom-Agnostic Moderation

I care about the writing of fans, not fandom internal politics or discourse. Write whatever you want, tag it honestly, and readers can find what they're looking for.

Expanded Content Warnings

The archive warnings have been updated to include:

  • Systemic Oppression
  • Colonialism
  • Ableism
  • Homophobia/Transphobia
  • Racism
  • Real Person Fiction

Expanded Relationship Tags

Relationship categories include:

  • Aromantic/Asexual Spectrum
  • QPR (Queer Platonic Relationship)
  • Non-Binary/Genderqueer Focus
  • Poly/Ensemble
  • Casual
  • Getting-Together

All Tags Are Canonical

Every tag you create goes into the searchable record—no volunteer wrangling required.

Technical Stack

This fork runs on a complex stack containerized with Docker Compose:

  • Ruby on Rails 8.1.0 on Ruby 3.4.6
  • MariaDB for the database
  • Redis for caching and job queue
  • Elasticsearch 7.17.5 for work search (2GB RAM requirement)
  • Memcached for fragment caching
  • Resque for background jobs with scheduler
  • Cloudflare Tunnel for HTTPS/SSL without port forwarding

Deployment Architecture

The archive is deployed on a homelab server (Apple Silicon M4) behind a Cloudflare Tunnel:

  • SSL termination handled by Cloudflare at the edge
  • No port forwarding required—home ports stay closed
  • Container isolation for all services
  • Automated backups via cron scripts

Deployment

Prerequisites

  • Docker with Rosetta enabled (for Apple Silicon)
  • Cloudflare account with domain configured
  • At least 6 GB RAM allocated to Docker
  • 20-30 GB free disk space

Quick Start

  1. Configure environment:

    cp .env.example .env
    # Edit .env with your secrets
    
  2. Configure Cloudflare Tunnel:

    • Create tunnel in Cloudflare Zero Trust
    • Add public hostnames pointing to http://web_prod:3000
    • Add tunnel token to .env
  3. Initialize database:

    docker compose run web_prod script/reset_database-prod.sh
    docker compose exec web_prod bundle exec rake db:schema:load
    docker compose exec web_prod bundle exec rails runner script/ensure_required_tags.rb
    docker compose exec web_prod bundle exec rake skins:load_site_skins
    
  4. Create admin account:

    docker compose exec web_prod bundle exec rails runner script/create_admin.rb
    
  5. Start services:

    docker compose up -d web_prod worker sc cloudflared
    

Services

  • web_prod — Rails application server
  • worker — Resque background job worker
  • sc — Resque scheduler for recurring tasks
  • cloudflared — Cloudflare Tunnel daemon
  • db — MariaDB database
  • es — Elasticsearch 7.17.5 (amd64 emulation on ARM64)
  • redis — Redis for caching and job queue
  • mc — Memcached for fragment caching

Important Technical Notes

CSS in Database

The site uses a custom skin system where CSS is stored in the database (Skin model), not in files. To update styles:

  1. Update CSS files locally for reference
  2. Update the database skin via Rails runner:
    docker exec fanfiction-web bundle exec rails runner 'skin = Skin.find_by_title("fanfiction.lol"); css = skin.css; css.gsub!("old", "new"); skin.save(validate: false)'
    
  3. Clear Rails cache: docker exec fanfiction-web bundle exec rails runner 'Rails.cache.clear'
  4. Restart container: docker compose restart fanfiction-web
  5. Purge Cloudflare cache

Elasticsearch Indexing

Elasticsearch 7.17.5 is required (gem pins 7.17.1). On Apple Silicon, it runs with Rosetta emulation. After database changes, reload Elasticsearch:

docker compose run web_prod bin/reload_elastic

Tag System

All tags are set to canonical: true by default for immediate searchability. The tagging system is the same robust AO3 system but without volunteer wrangling bottlenecks.

About the Original OTW-Archive

The OTW-Archive software is developed by the Organization for Transformative Works, a nonprofit organization by and for fans. You can see the original in action on Archive of Our Own.

For detailed setup notes for the original codebase, see SquidgeWorld's guide.

Contributing

This is a personal project, but I welcome feedback and issues. The upstream OTW-Archive has a Contributing Guidelines if you want to contribute to the original codebase.

License

The Archive code is licensed under GPL-2.0-or-later by the Organization for Transformative Works.

Acknowledgments


Write whatever the hell you want!