Skip to content

Settings reference

A lookup table for the Django settings specific to LCOJ, VNOJ, and DMOJ: the default in settings.py, the value on luyencode.net, what each setting does, and which page explains it in detail.

⏱ ~5 min · 👤 Operators · 🔑 Permission to edit local_settings.py on the server

When you need this page

  • You want to know which setting controls a site behavior (the pending-submission limit, the maximum number of test cases, who can comment...).
  • You plan to turn on a feature that's currently off (contest data download, MOSS, the sync API, Discord webhooks...).
  • You ran into a setting in the source code and want to know whether the bundled configuration overrides it.

This page only covers settings specific to the judge platform. Generic Django settings (SECRET_KEY, DEBUG, DATABASES, CACHES...) and the variables in the .env files are covered in Environment variables.

How to read the tables:

  • Default: the value in dmoj/repo/dmoj/settings.py. "not defined" means settings.py has no such line and the code falls back to a built-in value.
  • luyencode.net: the value in the bundled local_settings.py (template dmoj/config/local_settings.py), which is also what runs on luyencode.net. = means that file doesn't override the default. env X means the value is read from the environment variable X. `<secret>` marks a secret value you set yourself.

How to change a setting

Django loads configuration in three layers, and each layer overrides the one before it:

  1. dmoj/repo/dmoj/settings.py holds the defaults. Don't edit it; it belongs to the lcoj-site submodule.
  2. The running file is dmoj/repo/dmoj/local_settings.py. ./scripts/initialize copies it from the template dmoj/config/local_settings.py, and re-running initialize overwrites the running copy. When you make a change, apply it to both files.
  3. Some settings in local_settings.py are read from environment variables (HOST, SITE_FULL_URL, MEDIA_URL, EVENT_DAEMON_POST, CELERY_BROKER_URL, BRIDGED_HOST, MOSS_API_KEY, the Google OAuth credentials...). Change those in environment/site.env instead; see Environment variables.

Add a new setting at the end of local_settings.py (the Custom Configuration section), for example:

python
DMOJ_SUBMISSION_LIMIT = 3

For secrets, read the value from the environment instead of hard-coding it:

python
GLOBAL_API_KEY = os.environ.get('GLOBAL_API_KEY', '')

After editing local_settings.py, restart the services that run Django (from dmoj/):

sh
docker compose restart site celery
# also restart bridged if you changed BRIDGED_* or anything related to the judging queue
docker compose restart bridged

If you edit a .env file, recreate the containers with docker compose up -d ..., because restart doesn't re-read env_file (see Applying changes).

Site and branding

SettingDefaultluyencode.netWhat it doesDocs
SITE_NAME'DMOJ''LCOJ'Short name shown in page titles, the navbar, and emailsSite configuration
SITE_LONG_NAME'DMOJ: Modern Online Judge''LCOJ: Luyện Code Online Judge'Full site nameSite configuration
HOSTnot definedenv HOST (default 'localhost')Site domain; used to build ALLOWED_HOSTS and EVENT_DAEMON_GET(_SSL)Environment variables
SITE_FULL_URLNoneenv SITE_FULL_URL (default 'http://localhost/')Absolute base URL, used to build links in Discord webhooks and links to PDF and submission filesEnvironment variables
MEDIA_URL'' (Django)env MEDIA_URLBase URL for user-uploaded filesEnvironment variables
SITE_ADMIN_EMAIL'''[email protected]'Admin contact email shown on the site
SERVER_EMAIL'root@localhost' (Django)'LCOJ: Luyện Code Online Judge <[email protected]>'Sender address for error emailsEnvironment variables
LANGUAGE_CODE'en''vi'Default UI language
DEFAULT_USER_TIME_ZONE'America/Toronto''Asia/Ho_Chi_Minh'Time zone for new accounts
DMOJ_SSL1=Scheme for canonical links: 0 always http, 1 follows the request, 2 always httpsSettings with gotchas
DMOJ_CANONICAL'oj.luyencode.net'=Domain used in <link rel="canonical"> and og:urlSettings with gotchas
TIMEZONE_MAPan image on static.dmoj.cathe Blue Marble image on WikimediaMap used to pick a time zone on the profile page
ACE_URL, JQUERY_JS, SELECT2_JS_URL, SELECT2_CSS_URLcopies in /static/vnoj/ and the Google CDNcopies on cdnjs.cloudflare.comWhere the Ace code editor, jQuery, and Select2 load from
DMOJ_THEME_CSS, DMOJ_THEME_DEFAULT_ACE_THEME, DMOJ_SELECT2_THEMECSS style.css / dark/style.css, Ace github / twilight, Select2 dmoj=CSS files and editor themes for the light and dark themes
SITE_THEME_COOKIE_NAME, SITE_THEME_COOKIE_AGE'site_theme', 1 year=Cookie that remembers the light/dark theme for logged-out visitors
VNOJ_HOMEPAGE_TOP_USERS_COUNT5=Number of users in the compact leaderboard on the home page
DMOJ_BLOG_NEW_PROBLEM_COUNT7=Number of new problems in the sidebar of the home page and organization pages

Accounts and sign-in

SettingDefaultluyencode.netWhat it doesDocs
OAUTH_ONLYFalseTrueHides the password sign-up form, leaving only the Google sign-up buttonYour account
REGISTRATION_OPENTrue=False hides the Sign up link and blocks /accounts/register/Managing users
ACCOUNT_ACTIVATION_DAYS7=How many days an email activation link stays valid
SEND_ACTIVATION_EMAILnot defined (code treats it as True)=False activates password sign-ups immediately, without an email
TERMS_OF_SERVICE_URLNoneNoneTerms of service link on the sign-up form
BAD_MAIL_PROVIDERS, BAD_MAIL_PROVIDER_REGEX(), ()set(), =Email domains (or regexes) rejected at password sign-up
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY, SOCIAL_AUTH_GOOGLE_OAUTH2_SECRETnot defined<secret> (env vars of the same name)Google OAuth app credentials for sign-in and sign-upEnvironment variables
DMOJ_REQUIRE_STAFF_2FATrue=Stops staff from turning off their last two-factor authentication (2FA) methodSettings with gotchas
DMOJ_2FA_HARDCOREFalse=Shows a warning that admins won't help recover 2FA
DMOJ_TOTP_TOLERANCE_HALF_MINUTES1=Allowed clock drift for TOTP codes, in 30-second stepsYour account
DMOJ_SCRATCH_CODES_COUNT5=Number of backup codes generated when 2FA is enabledYour account
WEBAUTHN_RP_IDNone=Domain for security keys (WebAuthn); None hides the featureYour account
DMOJ_PASSWORD_RESET_LIMIT_WINDOW, DMOJ_PASSWORD_RESET_LIMIT_COUNT3600, 10=Each IP address can send at most 10 password reset requests per 3600 seconds
IMPERSONATE_REQUIRE_SUPERUSER, IMPERSONATE_DISABLE_LOGGINGTrue, True=Meant to restrict impersonation to superusers and turn off its log, but have no effectManaging users
DMOJ_USER_DATA_DOWNLOADFalseTrueLets users download their own dataUser data download
DMOJ_USER_DATA_CACHE, DMOJ_USER_DATA_INTERNAL'', '''/userdatacache', '/userdatacache'Directory for the ZIP files and the internal nginx path (X-Accel-Redirect) that serves themUser data download
DMOJ_USER_DATA_DOWNLOAD_RATELIMIT1 day1 dayMinimum time between two data requestsUser data download
VNOJ_DISPLAY_RANKSuser, setter, daor, staff, banned, admin, teacher=Display ranks shown next to usernamesManaging users
DMOJ_NEWSLETTER_ID_ON_REGISTERNone=Subscribes new users to a newsletter (needs the newsletter app, which isn't installed)
IP_BASED_AUTHENTICATION_HEADER'REMOTE_ADDR'=Header holding the IP for IP-based login; only takes effect if you add IPBasedAuthMiddleware (it isn't in the default MIDDLEWARE)

Problems and test data

SettingDefaultluyencode.netWhat it doesDocs
DMOJ_PROBLEM_DATA_ROOTNone'/problems/'Test data directory inside the container, matching the problems volumeManaging problems
DMOJ_PROBLEM_DATA_INTERNALnot defined=Internal nginx path for serving test files; when not defined, Django serves them itself
DMOJ_PROBLEM_MIN_TIME_LIMIT, DMOJ_PROBLEM_MAX_TIME_LIMIT0.01, 60 (seconds)=Allowed range for the time limitManaging problems
DMOJ_PROBLEM_MIN_MEMORY_LIMIT, DMOJ_PROBLEM_MAX_MEMORY_LIMIT0, 1048576 (KB)=Allowed range for the memory limitManaging problems
DMOJ_PROBLEM_MIN_PROBLEM_POINTS0=Minimum point value of a problem
VNOJ_PROBLEM_TIMELIMIT_LIMIT5 (seconds)=Highest time limit you can set without the high_problem_timelimit permissionPermissions
VNOJ_TESTCASE_HARD_LIMIT100=Maximum number of test cases without the create_mass_testcases permissionPermissions
VNOJ_TESTCASE_SOFT_LIMIT50=Above this many test cases, users without that permission get a warningPermissions
VNOJ_TESTCASE_VISIBLE_LENGTH60=Number of leading bytes of a test file shown in the preview
DMOJ_PROBLEM_STATEMENT_DISALLOWED_CHARACTERScurly quotes, the Unicode minus sign, ligatures such as , ...=Characters rejected in problem statements; saving a statement that contains them failsManaging problems
DMOJ_PROBLEM_HOT_PROBLEM_COUNT7=Number of "hot problems" (based on the last 24 hours) on the problem list
VNOJ_TAG_PROBLEM_MIN_RATING1900=Minimum rating needed to tag problemsCommunity
ENABLE_FTSFalseFalseEnables full-text search on the problem list
DATA_UPLOAD_MAX_NUMBER_FIELDS3000=Maximum number of fields in one form, raised so long test case tables can be saved
VNOJ_PROBLEM_DELETION_GRACE_PERIOD7 days=Soft-deleted problems older than this may be purged by the garbage collectorOrganizations
VNOJ_PROBLEM_GARBAGE_COLLECTOR_TIME_LIMIT1 hour=Maximum run time of one garbage collection pass
VNOJ_PROBLEM_GARBAGE_COLLECTOR_CRONTAB_KWARGS{'minute': 0, 'hour': 0}=Garbage collector schedule (needs Celery beat, see the gotcha)

Submissions and judging

SettingDefaultluyencode.netWhat it doesDocs
DMOJ_SUBMISSION_LIMIT2=Maximum pending submissions per user without the spam_submission permissionPermissions
DMOJ_SUBMISSIONS_REJUDGE_LIMIT10=Maximum submissions rejudged at once from the admin without the rejudge_submission_lot permissionPermissions
DMOJ_SUBMISSION_SOURCE_VISIBILITY'all-solved'=Who can view other users' source code on problems set to "follow global setting": 'all', 'all-solved', or 'only-own'Managing problems
DEFAULT_USER_LANGUAGE'CPP20'=Default programming language for new accounts
BRIDGED_JUDGE_ADDRESS[('localhost', 9999)][(env BRIDGED_HOST, 9999)], host defaults to bridgedWhere bridged listens for judge connectionsJudge setup
BRIDGED_DJANGO_ADDRESS[('localhost', 9998)][(env BRIDGED_HOST, 9998)], host defaults to bridgedWhere bridged listens for judging requests from the siteArchitecture
BRIDGED_DJANGO_CONNECT, BRIDGED_JUDGE_PROXIESNone, None=Address the site uses to reach bridged (if it differs from the listen address); trusted proxies in front of the judges
VNOJ_LONG_QUEUE_ALERT_THRESHOLD10=When the judging queue grows past this size, the on_long_queue webhook fires
VNOJ_LOW_POWER_MODEFalse=Low-power mode: caps the number of submission list pages and skips the heat map for users with too many submissions
VNOJ_LOW_POWER_MODE_CONFIG{'max_page': 5, 'heat_map_limit': 20000}=Parameters for low-power mode
DMOJ_STATS_SUBMISSION_RESULT_COLORScolors for AC, WA, TLE...=Result colors in statistics charts

Contests and rating

SettingDefaultluyencode.netWhat it doesDocs
VNOJ_CONTEST_DURATION_LIMIT14 (days)=Longest contest you can create without the long_contest_duration permissionContest setup
MAX_CONTEST_PROBLEMS_COUNTNone=Maximum number of problems in a contest; None means no limitContest setup
VNOJ_OFFICIAL_CONTEST_MODEFalse=Official contest mode: locks the name and "about" fields, logs the IP of every submission, and skips forced password changesContest setup
VNOJ_SHOULD_BAN_FOR_CHEATING_IN_CONTESTSFalse=Automatically bans users who are disqualified repeatedlyManaging users
VNOJ_MAX_DISQUALIFICATIONS_BEFORE_BANNING3=Number of disqualifications before a banManaging users
VNOJ_CONTEST_CHEATING_BAN_MESSAGE'Banned for multiple cheating offenses during contests'=Ban reason written to the profileManaging users
VNOJ_BAN_COUNT_FROM_DATEJan 1, 2026 (UTC)=Only disqualifications from contests starting on or after this date count; None counts all of themManaging users
DMOJ_CONTEST_DATA_DOWNLOADFalseTrueAllows contest data downloadsContest data download
DMOJ_CONTEST_DATA_CACHE, DMOJ_CONTEST_DATA_INTERNAL'', '''/contestdatacache', '/contestdatacache'Directory for the ZIP files and the internal nginx path that serves themContest data download
DMOJ_CONTEST_DATA_DOWNLOAD_RATELIMIT1 day1 dayMinimum time between two contest data requestsContest data download
CONTEST_REPLAY_MEDIA_DIR, DMOJ_CONTEST_REPLAY_INTERNAL'contest_replay', None=Directory (under MEDIA_ROOT) for scoreboard replay data; internal nginx path that serves itContest setup
DMOJ_PP_STEP, DMOJ_PP_ENTRIES0.98514, 300=Decay factor and number of best problems counted toward a user's performance points
DMOJ_PP_BONUS_FUNCTION0.05 * n=Bonus points based on the number of solved problems n
DMOJ_RATING_COLORSTrue=Colors usernames by rating

Organizations and quotas

SettingDefaultluyencode.netWhat it doesDocs
DMOJ_USER_MAX_ORGANIZATION_COUNT3=Maximum number of public (open) organizations a user can joinOrganizations
VNOJ_ORGANIZATION_ADMIN_LIMIT3=How many organizations a user can administer and still create a new one, without the spam_organization permissionOrganizations
VNOJ_ORG_PP_STEP, VNOJ_ORG_PP_ENTRIES, VNOJ_ORG_PP_SCALE0.95, 100, 1=Organization points formula, computed from its top members' pointsOrganizations
VNOJ_ENABLE_ORGANIZATION_CREDIT_LIMITATIONFalse=Enables the credit system: an organization out of credit can't submit to its private problemsOrganizations
VNOJ_MONTHLY_FREE_CREDIT10800 (3 judging hours)=Free credit per organization per monthOrganizations
VNOJ_PRICE_PER_HOUR50=Price (in thousand VND) per judging hour beyond the free credit, used in the cost chartOrganizations
VNOJ_ORGANIZATION_DEFAULT_MAX_PROBLEMS, VNOJ_ORGANIZATION_DEFAULT_MAX_STORAGE1000, 5 GB=Default quota for problem count and test data storage of a new organizationOrganizations
VNOJ_QUOTA_WARNING_THRESHOLD0.8=Shows a warning once 80% of a quota is usedOrganizations
VNOJ_QUOTA_WARNING_SUFFIX''=HTML appended to every quota warning (for example, a link to a guide)Organizations
VNOJ_QUOTA_ENFORCEMENT_ENABLEDFalse=True blocks creating problems and uploading test data over quota; False only warnsOrganizations
VNOJ_QUOTA_PACKAGE_STORAGE, VNOJ_QUOTA_PACKAGE_PROBLEMS5 GB, 1000=Storage and problem count added by each extra quota packageOrganizations
GROUP_PERMISSION_FOR_ORG_ADMIN'Org Admin'=Django permission group automatically given to organization adminsPermissions
DESCRIPTION_MAX_LENGTH200=Length of the meta description taken from an organization's "about" text
VNOJ_IGNORED_ORGANIZATION_SUBDOMAINS['oj', 'www', 'localhost']=Subdomains not treated as organizations; only takes effect if you add OrganizationSubdomainMiddleware (it isn't in the default MIDDLEWARE)

Comments, blog, and contribution

SettingDefaultluyencode.netWhat it doesDocs
VNOJ_INTERACT_MIN_PROBLEM_COUNT5=Problems a user must solve before they can comment, vote, and edit their profileCommunity
VNOJ_BLOG_MIN_PROBLEM_COUNT10=Problems a user must solve before they can write blog postsCommunity
VNOJ_COMMENT_MIN_CONTRIBUTION-20=Minimum contribution points needed to comment (doesn't apply to staff)Community
VNOJ_COMMENT_MIN_LENGTH, VNOJ_COMMENT_MAX_LENGTH10, 8196=Minimum and maximum comment length (doesn't apply to staff)Community
VNOJ_COMMENT_BLACKLIST_TERMS[]=Case-insensitive terms that are banned in comments
VNOJ_COMMENT_RATE_LIMIT_COUNT, VNOJ_COMMENT_RATE_LIMIT_WINDOWNone, 600 seconds=Maximum comments within a time window; None means no limit
DMOJ_COMMENT_VOTE_HIDE_THRESHOLD-5=Comments scored at or below this threshold are collapsedCommunity
DMOJ_COMMENT_REPLY_TIMEFRAME365 days=Users can only reply to comments posted within this period (except those allowed to edit comments)Community
VNOJ_CP_COMMENT1=Contribution points per vote point on comments and blog postsCommunity
VNOJ_CP_TICKET105Contribution points per ticket marked as helpfulCommunity
VNOJ_CP_EDITORIAL_REVEALnot defined (code uses 1)=Contribution points deducted each time a user opens an editorial before solving the problemEditorials
TICKET_AUTOFILL_REPLIESa list of canned replies=Canned replies offered when handling someone else's ticket
NOFOLLOW_EXCLUDEDset()=Domains that don't get rel="nofollow" when Markdown is rendered
GOOGLE_SEARCH_ENGINE_URLNone=Google Custom Search URL for the search box on the home page

Quiz, exam library, and URL shortener

Quizzes have no settings of their own; everything is configured in the admin (see Quiz authoring).

SettingDefaultluyencode.netWhat it doesDocs
URLSHORTENER_DOMAINnot defined=Custom domain for short links; without it, copied links are just /<code>URL shortener
PDF_STATEMENT_MAX_FILE_SIZE5242880 (5 MB)=Maximum size of a PDF statement or exam library fileExam library
PDF_STATEMENT_SAFE_EXTS{'pdf'}=File extensions allowed for uploadExam library
PDF_STATEMENT_UPLOAD_MEDIA_DIR, PDF_STATEMENT_UPLOAD_URL_PREFIX'pdf', '/pdf'=Directory (under MEDIA_ROOT) and URL prefix for uploaded PDFsExam library

Rendering (math, PDF, images)

SettingDefaultluyencode.netWhat it doesDocs
MATHOID_URLFalse=Mathoid service URL; with False, math is rendered in the browser by MathJaxMathoid
MATHOID_GZIP, MATHOID_MML_CACHE, MATHOID_CSS_CACHE, MATHOID_DEFAULT_TYPE, MATHOID_MML_CACHE_TTL, MATHOID_CACHE_ROOT, MATHOID_CACHE_URLFalse, None, 'default', 'auto', 86400, '', False=Mathoid caching and output typeMathoid
TEXOID_URLnot defined=Texoid service URL (TikZ drawings); not currently wired into statement renderingTexoid
TEXOID_GZIP, TEXOID_META_CACHE, TEXOID_META_CACHE_TTL, TEXOID_CACHE_ROOT, TEXOID_CACHE_URLFalse, 'default', 86400, not defined, not defined=Texoid cachingTexoid
DMOJ_PDF_PDFOID_URLNone=Pdfoid service URL; anything other than None enables PDF statement downloadsPdfoid
DMOJ_PDF_PROBLEM_CACHE, DMOJ_PDF_PROBLEM_INTERNALNone, None=PDF cache directory and the internal nginx path that serves itPdfoid
DMOJ_CAMO_URL, DMOJ_CAMO_KEYNone, None=Camo image proxy for external images in Markdown; the key is a <secret>SSL content proxy
DMOJ_CAMO_HTTPS, DMOJ_CAMO_EXCLUDEFalse, ()=Use https for protocol-relative URLs; domains that bypass CamoSSL content proxy

Integrations and API

SettingDefaultluyencode.netWhat it doesDocs
MOSS_API_KEYNone<secret> (env MOSS_API_KEY, default '')MOSS key for contest plagiarism checksContest setup
MOSS_HOST, MOSS_PORT'moss.stanford.edu', 7690=MOSS server
OPENAI_API_KEY, OPENAI_BASE_URLnot Django settingsenvironment variables at run timeKey and base URL of an OpenAI-compatible API, read straight from the environment by the generate_editorials commandEditorials, Management commands
VNOJ_ENABLE_SYNC_APIFalse=Enables the contest sync API under /api/v2/API
GLOBAL_API_KEYa public test value=Shared key that every sync API request must sendAPI
DISCORD_WEBHOOKevery key is None=Discord webhook URL per event (tickets, comments, new problems, long queue...); the values are <secret>Settings with gotchas
VNOJ_DISCORD_WEBHOOK_THROTTLING(10, 60)=At most 10 error messages to Discord per 60 seconds
OJ_PROBLEM_PRESET, OJ_LISTCodeforces, Codeforces Gym, AtCoder, VNOJ, Kattis=External judges and their problem URL patterns, recognized by the problem tagging feature
OJ_REQUESTS_TIMEOUT, OJAPI_CACHE_TIMEOUT5 seconds, 3600 seconds=Request timeout and cache lifetime for calls to external judge APIs

Background tasks and caching

SettingDefaultluyencode.netWhat it doesDocs
CELERY_BROKER_URL, CELERY_RESULT_BACKENDnot definedenv vars of the same name, default redis://redis:6379/1Celery task queue and result storeEnvironment variables
CELERY_BROKER_URL_SECRETnot defined=If set, overrides the broker URL (for URLs that contain a password)
CELERY_TIMEZONE, CELERY_WORKER_HIJACK_ROOT_LOGGER'UTC', False=Time zone for periodic task schedules; keeps Celery from taking over the root logger
CACHES{}Redis, env REDIS_CACHING_URLDjango cacheEnvironment variables
EVENT_DAEMON_USEFalseTrueEnables live updates (judging results, scoreboards) through wseventArchitecture
EVENT_DAEMON_POST'ws://localhost:9997/'env EVENT_DAEMON_POST (default 'ws://wsevent:15101/')Where the site publishes events to wseventEnvironment variables
EVENT_DAEMON_GET, EVENT_DAEMON_GET_SSL'ws://localhost:9996/', not definedws://{HOST}/event/, wss://{HOST}/event/WebSocket URL browsers connect toEnvironment variables
EVENT_DAEMON_POLL'/channels/''/channels/'Long-polling path used when WebSockets aren't available
EVENT_DAEMON_KEY, EVENT_DAEMON_AMQP, EVENT_DAEMON_AMQP_EXCHANGENone, not defined, 'dmoj-events'=Auth key for wsevent; settings for the AMQP-based event server (not used with wsevent)
EVENT_DAEMON_SUBMISSION_KEY, EVENT_DAEMON_CONTEST_KEY, EVENT_DAEMON_TICKET_KEY, EVENT_DAEMON_NOTIFICATION_KEYfixed strings in settings.py=HMAC keys that derive the private event channel names for submissions, contests, tickets, and notificationsSettings with gotchas
DMOJ_EMAIL_THROTTLING(10, 60)=At most 10 error emails per 60 seconds

Settings with gotchas

  • IMPERSONATE_* is ignored. django-impersonate (1.9.x in the image) only reads the IMPERSONATE = {...} dict, not IMPERSONATE_REQUIRE_SUPERUSER or IMPERSONATE_DISABLE_LOGGING. As a result, any staff member can impersonate non-superusers, and impersonation is still logged. Managing users shows how to fix it.
  • Setting MATHOID_URL breaks math. With MATHOID_URL set, the renderer switches to mml output and MathJax isn't loaded, so many browsers show the raw ~a+b~. Keep the default False (see Mathoid).
  • TEXOID_URL is checked with hasattr. To turn it off, delete the line; TEXOID_URL = None still counts as enabled.
  • GLOBAL_API_KEY defaults to a public value. The value in settings.py is in a public repository, and the bundled local_settings.py doesn't override it. The sync API is off, so this is harmless today, but before you set VNOJ_ENABLE_SYNC_API = True you must set your own key, read from an environment variable (see API).
  • The EVENT_DAEMON_*_KEY values are public too. They derive the private event channel names, so anyone who knows them can compute a channel name. Set your own values, read from environment variables.
  • DMOJ_REQUIRE_STAFF_2FA only blocks turning 2FA off. Staff without 2FA can still sign in and work normally; the setting only stops staff from removing their last 2FA method (TOTP or security key).
  • OAUTH_ONLY only hides the form. Only the sign-up template reads it, to hide the input fields; the /accounts/register/ view still accepts a POST. To block password sign-ups completely, also set REGISTRATION_OPEN = False (which also hides the Sign up link in the navbar). Password login keeps working either way.
  • An empty MOSS_API_KEY still counts as configured. The code checks MOSS_API_KEY is not None, while the bundled local_settings.py reads os.environ.get('MOSS_API_KEY', ''). Without the environment variable, the value is '', so the MOSS tab still shows for users with moss_contest, but running MOSS fails.
  • DMOJ_SSL = 1 when HTTPS ends before nginx. If a proxy, CDN, or load balancer in front of nginx handles HTTPS and forwards plain HTTP, Django can't tell the original request was HTTPS (SECURE_PROXY_SSL_HEADER isn't set). As a result, canonical links use http://, and pages get the EVENT_DAEMON_GET (ws://) address instead of EVENT_DAEMON_GET_SSL. If the site is only served over HTTPS, set DMOJ_SSL = 2; for pages to use wss://, have the proxy send a scheme header and set SECURE_PROXY_SSL_HEADER to match. The #DMOJ_HTTPS line in local_settings.py is only a comment; the code reads DMOJ_SSL.
  • DMOJ_CANONICAL defaults to oj.luyencode.net. The value lives in settings.py and isn't derived from HOST. If you run the site on a different domain, set DMOJ_CANONICAL to your domain, or canonical links and og:url will point to someone else's domain.
  • There is no Celery beat. The celery container runs only celery worker, not beat. Periodic tasks (purging soft-deleted problems on the VNOJ_PROBLEM_GARBAGE_COLLECTOR_CRONTAB_KWARGS schedule, resetting organization credit on the 1st of each month, the daily queue time stats) never run on their own, so changing those schedule settings does nothing.
  • DISCORD_WEBHOOK['default'] isn't a fallback. The code only reads the exact key for each event (on_new_ticket, on_new_ticket_message, on_new_comment, on_new_problem, on_new_tag_problem, on_new_tag, on_new_contest, on_new_blogpost, on_long_queue, queue_time_stats, on_error). Webhooks are also only sent when SITE_FULL_URL isn't None; message links are built as SITE_FULL_URL + '/user/...', so a trailing / in the URL produces //.
  • VNOJ_DISPLAY_RANKS is used in a migration. Changing the list requires a new migration (./scripts/manage.py makemigrations).
  • NGINX_PORT isn't a Django setting. It's a Docker Compose variable that belongs in dmoj/.env, not in local_settings.py or site.env (see Environment variables).

Next steps