- Ruby 56.6%
- Gherkin 19.8%
- HTML 15.6%
- JavaScript 5.6%
- CSS 2.1%
- Other 0.3%
|
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
|
||
|---|---|---|
| .git-rewrite | ||
| .github | ||
| app | ||
| bin | ||
| config | ||
| db | ||
| entrypoints | ||
| factories | ||
| features | ||
| lib | ||
| log | ||
| public | ||
| rubocop | ||
| script | ||
| scripts | ||
| spec | ||
| test | ||
| .codeclimate.yml | ||
| .codecov.yml | ||
| .devcontainer.json | ||
| .env.example | ||
| .erb-lint.yml | ||
| .gitattributes | ||
| .gitignore | ||
| .hound.yml | ||
| .jshintignore | ||
| .jshintrc | ||
| .phrase.yml | ||
| .rubocop.yml | ||
| .ruby-version | ||
| .simplecov | ||
| ACKNOWLEDGMENTS.md | ||
| cafe-server-notes.md | ||
| Capfile | ||
| config.ru | ||
| CONTRIBUTING.md | ||
| docker-compose.yml | ||
| fflol-logo-white.png | ||
| fflol-logo.png | ||
| Gemfile | ||
| Gemfile.lock | ||
| LICENSE | ||
| Rakefile | ||
| README.md | ||
| SECURITY.md | ||
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
-
Configure environment:
cp .env.example .env # Edit .env with your secrets -
Configure Cloudflare Tunnel:
- Create tunnel in Cloudflare Zero Trust
- Add public hostnames pointing to
http://web_prod:3000 - Add tunnel token to
.env
-
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 -
Create admin account:
docker compose exec web_prod bundle exec rails runner script/create_admin.rb -
Start services:
docker compose up -d web_prod worker sc cloudflared
Services
web_prod— Rails application serverworker— Resque background job workersc— Resque scheduler for recurring taskscloudflared— Cloudflare Tunnel daemondb— MariaDB databasees— Elasticsearch 7.17.5 (amd64 emulation on ARM64)redis— Redis for caching and job queuemc— 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:
- Update CSS files locally for reference
- 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)' - Clear Rails cache:
docker exec fanfiction-web bundle exec rails runner 'Rails.cache.clear' - Restart container:
docker compose restart fanfiction-web - 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.
- Report issues: source.tube/brennan/fanfiction.lol/issues
- Contact: mail@brennanbrown.ca
- Mastodon: @brennan@social.lol
License
The Archive code is licensed under GPL-2.0-or-later by the Organization for Transformative Works.
Acknowledgments
- The Organization for Transformative Works for creating and maintaining the OTW-Archive
- SquidgeWorld for the foundational setup guide
- Melo for the deployment guide
- The entire AO3 community for building the infrastructure that makes this possible
Write whatever the hell you want!