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. https://fanfiction.lol
  • Ruby 56%
  • Gherkin 19.6%
  • HTML 16.1%
  • JavaScript 5.5%
  • CSS 2.5%
  • Other 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Brennan Kenneth Brown 5108e0d200
Some checks failed
Automated Tests / rspec --exclude-pattern 'spec/{controllers,models}/**/*.rb' (push) Has been cancelled
Automated Tests / rake db:otwseed (push) Has been cancelled
Automated Tests / cucumber features/admins (push) Has been cancelled
Automated Tests / cucumber features/bookmarks (push) Has been cancelled
Automated Tests / cucumber features/collections (push) Has been cancelled
Automated Tests / cucumber features/comments_and_kudos (push) Has been cancelled
Automated Tests / cucumber features/gift_exchanges (push) Has been cancelled
Automated Tests / cucumber features/importing (push) Has been cancelled
Automated Tests / cucumber features/other_a (push) Has been cancelled
Automated Tests / cucumber features/other_b (push) Has been cancelled
Automated Tests / cucumber features/prompt_memes_a (push) Has been cancelled
Automated Tests / cucumber features/prompt_memes_b (push) Has been cancelled
Automated Tests / cucumber features/prompt_memes_c (push) Has been cancelled
Automated Tests / cucumber features/search (push) Has been cancelled
Automated Tests / cucumber features/tag_sets (push) Has been cancelled
Automated Tests / cucumber features/tags_and_wrangling (push) Has been cancelled
Automated Tests / cucumber features/users (push) Has been cancelled
Automated Tests / cucumber features/works (push) Has been cancelled
Automated Tests / rspec spec/controllers (push) Has been cancelled
Automated Tests / rspec spec/models (push) Has been cancelled
Brakeman Scan / Brakeman Scan (push) Has been cancelled
Fix: Exclude chapter-level summaries and notes from story text
- Target .userstuff[role="article"] specifically for chapter content
- Previously extracted from entire chapter div, including summary/notes modules
- Fixes issue where chapter summaries appeared in fic text
- Fixes issue where chapter notes appeared in fic text
- Maintains fallback to .userstuff if role="article" not found
2026-07-08 16:14:14 -11:00
.github AO3-7475 Stop using cache-apt-pkgs-action in automated tests (#5830) 2026-05-23 10:48:29 +02:00
app Fix: Exclude chapter-level summaries and notes from story text 2026-07-08 16:14:14 -11:00
bin Add Docker deployment infrastructure and scripts 2026-05-29 00:44:12 -06:00
config Improve AO3 story parser and remove AO3 from permitted hosts 2026-07-01 20:14:36 -06:00
db Add Y/N (Reader Insert) category support 2026-06-03 23:53:20 -06: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 home pages, disable dynamic scheduler, fix collection header styling, add orphan tag cleanup script 2026-06-08 11:02:06 -06:00
log Gitkeep the log dir 2011-02-09 16:33:41 -06:00
public Update category tag badge CSS for light and dark themes 2026-07-01 20:14:46 -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 Update ensure_required_tags seed script for new and renamed tags 2026-07-01 20:13:52 -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 Update gitignore to exclude local preview files 2026-06-03 23:54:08 -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 Update Ruby version to 3.3.0 to match production server 2026-06-06 02:02:02 -11: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
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 Use env var for MySQL password in docker-compose 2026-06-06 02:02:06 -11: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 Update home pages, disable dynamic scheduler, fix collection header styling, add orphan tag cleanup script 2026-06-08 11:02:06 -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. Created by Brennan, a Queer Red River Métis author and web developer, because fandom writing deserves independent, free infrastructure.

Live site: fanfiction.lol
Source code: source.tube/brennan/fanfiction.lol
Contact: mail@brennanbrown.ca

What Makes This Fork Different?

No Invite Queue

Anyone can register immediately, no waiting list, no queue. Sign up and start posting.

Fandom and Discourse Agnostic

This archive cares about the writing of fans, not fandom internal politics or discourse. Write whatever you want, tag it honestly so readers can find what they're looking for and avoid what they'd rather avoid. There are many other places on the internet for those conversations, just not here.

Expanded Content Warnings

Content warnings are important signals for readers who need them. The archive warnings include:

  • Graphic Depictions Of Violence
  • Major Character Death
  • Rape/Non-Con
  • Ableism
  • Colonialism
  • Queerphobia
  • Misogyny
  • Racism
  • Systemic Oppression
  • Real Person Fiction (RPF)
  • Incest

Expanded Relationship Tags

The tagging system reflects the full range of what people actually write:

  • F/F (Female/Female, Femslash, Lesbian, Sapphic)
  • F/M (Female/Male, Het, Heterosexual)
  • M/M (Male/Male, Slash, Gay, Queer)
  • Gen (General, no romantic or sexual relationships)
  • Multi (Multiple relationship tags)
  • Other (Unconventional dynamics, complex relationship structures)
  • Poly/Ensemble (Polyamorous relationships, ensemble casts)
  • Asexual (Asexual spectrum, Ace)
  • Aromantic (Aromantic spectrum, Aro)
  • QPR (Queerplatonic Relationship)
  • Queer (Other queer relationships or identities)
  • Getting Together (Developing romantic relationship)

Nearly All Tags Are Canonical

Every tag you create goes into the searchable record.

Technical Stack

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

  • Ruby on Rails 8.1.2.1 on Ruby 3.4.6
  • MariaDB 10.5.4 for the database
  • Redis 7.4.9 for caching and job queue
  • Elasticsearch 7.17.9 for work search (2GB RAM requirement)
  • Memcached 1.5.22 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 (Lubuntu on cafe) 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 29.1.3 or later
  • Cloudflare account with domain configured
  • At least 6 GB RAM allocated to Docker
  • 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.9 is required (gem pins 7.17.1). While initial development was on macOS with Rosetta emulation, the production deployment runs on Lubuntu (cafe) with native amd64. 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.

Other AO3 Forks

fanfiction.lol is one of several AO3 forks. Here are the others:

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.

fanfiction.lol is not affiliated with the Organization for Transformative Works or Archive of Our Own.

Contributing

This is a personal project, but I welcome feedback and issues. The upstream OTW-Archive has 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


love writing, love fandom!