Blocking Signup Spam with reCAPTCHA
Turn on the "I'm not a robot" box (reCAPTCHA v2) for the password signup form. You only need this after turning off
OAUTH_ONLY; LCOJ's default configuration doesn't need it.⏱ ~30 min · 👤 Operators · 🔑 SSH + docker access on the server, a Google account
Do you need this?
reCAPTCHA adds an "I'm not a robot" box to the username/password signup form to stop bots from creating junk accounts.
- LCOJ doesn't need reCAPTCHA today. The shipped config sets
OAUTH_ONLY = True, so the traditional signup form is hidden and users can only sign up through OAuth (Google). Google already verifies those accounts for you. - Only read on if you turn off
OAUTH_ONLYto reopen password-based signup.
Status in LCOJ
| Component | Status |
|---|---|
OAUTH_ONLY in dmoj/config/local_settings.py | True: the traditional signup form is hidden |
Python package django-recaptcha2 | Not installed: not in requirements.txt or additional_requirements.txt |
RECAPTCHA_PUBLIC_KEY, RECAPTCHA_PRIVATE_KEY | Not set |
| Result | reCAPTCHA is off |
How LCOJ integrates reCAPTCHA
LCOJ decides whether to show a captcha like this:
- LCOJ tries to import
snowpenguin.django.recaptcha2. That module comes from the PyPI packagedjango-recaptcha2. - If the import succeeds and settings has a
RECAPTCHA_PRIVATE_KEYattribute, the signup form gets acaptchafield (a reCAPTCHA v2 checkbox widget). - If either condition is missing, the form has no captcha and nothing is reported.
Don't mix up the two packages
- LCOJ uses
django-recaptcha2(modulesnowpenguin.django.recaptcha2), which supports reCAPTCHA v2 only. - The
django-recaptchapackage (moduledjango_recaptcha, which has reCAPTCHA v3) is not used by LCOJ. Installing it won't make a captcha appear.
A note on OAUTH_ONLY
OAUTH_ONLY currently only hides the input fields on the signup page; /accounts/register/ still accepts a signup form posted to it directly. If you're worried about bots posting the form directly, enable reCAPTCHA as described on this page.
Before you start
Enabling reCAPTCHA (only after turning off OAUTH_ONLY)
Try it on a development machine first
django-recaptcha2 (latest release 1.4.1) only declares support up to Django 2.1, while LCOJ runs Django 4.2. Try it on a development machine before enabling it in production.
Step 1: Get keys from Google
- Go to the reCAPTCHA admin and sign in with a Google account.
- Create a new site:
- Label:
LCOJ - Type: reCAPTCHA v2, "I'm not a robot" Checkbox
- Domains: your domain, for example
lcoj.example.com(add your dev domain if needed)
- Label:
- Keep the Site key (public) and Secret key (private).
Step 2: Install the Python package
Add one line to dmoj/repo/additional_requirements.txt:
django-recaptcha2Then rebuild the images (from the dmoj/ directory):
docker compose up -d --build base site celeryStep 3: Put the keys in the configuration
local_settings.py does not read RECAPTCHA_* from environment variables on its own. To keep secrets out of the file, read them from the environment explicitly.
Add to
dmoj/environment/site.env:envRECAPTCHA_PUBLIC_KEY=<site key> RECAPTCHA_PRIVATE_KEY=<secret key>Add to
dmoj/config/local_settings.py, then copy it todmoj/repo/dmoj/local_settings.py(the file the site actually reads):pythonif os.environ.get('RECAPTCHA_PRIVATE_KEY'): INSTALLED_APPS += ('snowpenguin.django.recaptcha2',) RECAPTCHA_PUBLIC_KEY = os.environ['RECAPTCHA_PUBLIC_KEY'] RECAPTCHA_PRIVATE_KEY = os.environ['RECAPTCHA_PRIVATE_KEY']- The
ifblock matters: LCOJ enables the captcha as soon asRECAPTCHA_PRIVATE_KEYexists, even if it's empty. INSTALLED_APPSneeds this app so thesnowpenguin/recaptcha/recaptcha_init.htmltemplate can be found.
- The
Set
OAUTH_ONLY = Falseif you want to reopen the password signup form.
See also Environment and configuration.
Step 4: Restart
docker compose restart does not reread site.env. Use up -d to recreate the containers:
cd dmoj
docker compose up -d site celeryVerify
- Open
https://lcoj.example.com/accounts/register/in a private window. - The "I'm not a robot" box appears at the bottom of the form.
- Try registering a test account.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| No captcha box | OAUTH_ONLY = True (form hidden), django-recaptcha2 not installed, or RECAPTCHA_PRIVATE_KEY missing | Check each condition above |
Error 500 TemplateDoesNotExist | 'snowpenguin.django.recaptcha2' missing from INSTALLED_APPS | Add it as in Step 3 |
Import error when site starts | The package is incompatible with Django 4.2 | Remove it from additional_requirements.txt, rebuild, and keep OAUTH_ONLY = True |
| Google says "Invalid domain for site key" | Domain not registered in the reCAPTCHA admin | Add the domain and retry |
| Captcha always fails | Wrong secret key, or the container has no internet access | Check site.env, see docker compose logs -f site |
Security
- Never commit the secret key to git. Keep it in
dmoj/environment/site.env(already gitignored). - Watch new-account counts to catch spam early.
Next steps
- Environment and configuration: how
site.envandlocal_settings.pywork together. - Updating LCOJ: rebuild images after changing
additional_requirements.txt. - Managing users: clean up junk accounts that slipped through.
Need help?
Open an issue at github.com/luyencode/lcoj-docker/issues, find more at behitek.com, or contact us via luyencode.net/about/#lien-he.
