[{"data":1,"prerenderedAt":1559},["ShallowReactive",2],{"\u002Fdeploy\u002Fflask-production-config-basics":3},{"id":4,"title":5,"body":6,"description":1549,"extension":1550,"meta":1551,"navigation":93,"path":1555,"seo":1556,"stem":1557,"__hash__":1558},"content\u002Fdeploy\u002Fflask-production-config-basics.md","Flask Production Config Basics",{"type":7,"value":8,"toc":1531},"minimark",[9,13,17,22,25,197,200,218,225,251,254,258,264,268,971,976,1019,1026,1029,1045,1048,1062,1069,1078,1082,1137,1141,1144,1168,1171,1183,1186,1212,1218,1263,1266,1281,1284,1305,1308,1322,1325,1353,1357,1443,1447,1465,1469,1474,1486,1490,1493,1500,1503,1507,1513,1517,1520,1524,1527],[10,11,5],"h1",{"id":12},"flask-production-config-basics",[14,15,16],"p",{},"If you're preparing a Flask app for production or trying to fix risky default settings, this guide shows you how to set up core production configuration step-by-step. The outcome is a Flask app that runs with production-safe defaults, externalized secrets, and predictable behavior behind a WSGI server.",[18,19,21],"h2",{"id":20},"quick-fix-quick-setup","Quick Fix \u002F Quick Setup",[14,23,24],{},"Use this as the minimum production baseline:",[26,27,32],"pre",{"className":28,"code":29,"language":30,"meta":31,"style":31},"language-bash shiki shiki-themes github-light github-dark","# 1) Set required environment variables\nexport FLASK_ENV=production\nexport SECRET_KEY='change-this-to-a-long-random-value'\nexport DATABASE_URL='postgresql:\u002F\u002Fuser:pass@127.0.0.1:5432\u002Fappdb'\n\n# 2) Minimal production config example\ncat > config.py \u003C\u003C'EOF'\nimport os\n\nclass ProductionConfig:\n    DEBUG = False\n    TESTING = False\n    SECRET_KEY = os.environ['SECRET_KEY']\n    SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']\n    SQLALCHEMY_TRACK_MODIFICATIONS = False\n    SESSION_COOKIE_SECURE = True\n    SESSION_COOKIE_HTTPONLY = True\n    SESSION_COOKIE_SAMESITE = 'Lax'\n    PREFERRED_URL_SCHEME = 'https'\nEOF\n","bash","",[33,34,35,44,61,75,88,95,101,120,126,131,137,143,149,155,161,167,173,179,185,191],"code",{"__ignoreMap":31},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sJ8bj","# 1) Set required environment variables\n",[36,45,47,51,55,58],{"class":38,"line":46},2,[36,48,50],{"class":49},"szBVR","export",[36,52,54],{"class":53},"sVt8B"," FLASK_ENV",[36,56,57],{"class":49},"=",[36,59,60],{"class":53},"production\n",[36,62,64,66,69,71],{"class":38,"line":63},3,[36,65,50],{"class":49},[36,67,68],{"class":53}," SECRET_KEY",[36,70,57],{"class":49},[36,72,74],{"class":73},"sZZnC","'change-this-to-a-long-random-value'\n",[36,76,78,80,83,85],{"class":38,"line":77},4,[36,79,50],{"class":49},[36,81,82],{"class":53}," DATABASE_URL",[36,84,57],{"class":49},[36,86,87],{"class":73},"'postgresql:\u002F\u002Fuser:pass@127.0.0.1:5432\u002Fappdb'\n",[36,89,91],{"class":38,"line":90},5,[36,92,94],{"emptyLinePlaceholder":93},true,"\n",[36,96,98],{"class":38,"line":97},6,[36,99,100],{"class":42},"# 2) Minimal production config example\n",[36,102,104,108,111,114,117],{"class":38,"line":103},7,[36,105,107],{"class":106},"sScJk","cat",[36,109,110],{"class":49}," >",[36,112,113],{"class":73}," config.py",[36,115,116],{"class":49}," \u003C\u003C",[36,118,119],{"class":73},"'EOF'\n",[36,121,123],{"class":38,"line":122},8,[36,124,125],{"class":73},"import os\n",[36,127,129],{"class":38,"line":128},9,[36,130,94],{"emptyLinePlaceholder":93},[36,132,134],{"class":38,"line":133},10,[36,135,136],{"class":73},"class ProductionConfig:\n",[36,138,140],{"class":38,"line":139},11,[36,141,142],{"class":73},"    DEBUG = False\n",[36,144,146],{"class":38,"line":145},12,[36,147,148],{"class":73},"    TESTING = False\n",[36,150,152],{"class":38,"line":151},13,[36,153,154],{"class":73},"    SECRET_KEY = os.environ['SECRET_KEY']\n",[36,156,158],{"class":38,"line":157},14,[36,159,160],{"class":73},"    SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']\n",[36,162,164],{"class":38,"line":163},15,[36,165,166],{"class":73},"    SQLALCHEMY_TRACK_MODIFICATIONS = False\n",[36,168,170],{"class":38,"line":169},16,[36,171,172],{"class":73},"    SESSION_COOKIE_SECURE = True\n",[36,174,176],{"class":38,"line":175},17,[36,177,178],{"class":73},"    SESSION_COOKIE_HTTPONLY = True\n",[36,180,182],{"class":38,"line":181},18,[36,183,184],{"class":73},"    SESSION_COOKIE_SAMESITE = 'Lax'\n",[36,186,188],{"class":38,"line":187},19,[36,189,190],{"class":73},"    PREFERRED_URL_SCHEME = 'https'\n",[36,192,194],{"class":38,"line":193},20,[36,195,196],{"class":73},"EOF\n",[14,198,199],{},"Load the config in your app factory:",[26,201,205],{"className":202,"code":203,"language":204,"meta":31,"style":31},"language-python shiki shiki-themes github-light github-dark","app.config.from_object('config.ProductionConfig')\n","python",[33,206,207],{"__ignoreMap":31},[36,208,209,212,215],{"class":38,"line":39},[36,210,211],{"class":53},"app.config.from_object(",[36,213,214],{"class":73},"'config.ProductionConfig'",[36,216,217],{"class":53},")\n",[14,219,220,221,224],{},"Run the app with Gunicorn, not ",[33,222,223],{},"flask run",":",[26,226,228],{"className":28,"code":227,"language":30,"meta":31,"style":31},"gunicorn -w 3 -b 127.0.0.1:8000 'wsgi:app'\n",[33,229,230],{"__ignoreMap":31},[36,231,232,235,239,242,245,248],{"class":38,"line":39},[36,233,234],{"class":106},"gunicorn",[36,236,238],{"class":237},"sj4cs"," -w",[36,240,241],{"class":237}," 3",[36,243,244],{"class":237}," -b",[36,246,247],{"class":73}," 127.0.0.1:8000",[36,249,250],{"class":73}," 'wsgi:app'\n",[14,252,253],{},"This covers the minimum production baseline: no debug mode, no hardcoded secrets, secure cookies, and a real WSGI server. Adjust the database URL and app import path for your project.",[18,255,257],{"id":256},"whats-happening","What’s Happening",[14,259,260,261,263],{},"Flask defaults are development-friendly, not production-safe. Most production configuration issues come from leaving debug mode enabled, hardcoding secrets, using SQLite beyond development, or starting the app with ",[33,262,223],{},". A production setup should separate code from secrets and load explicit settings for the runtime environment.",[18,265,267],{"id":266},"step-by-step-guide","Step-by-Step Guide",[269,270,271,480,539,670,714,761,791,890,925,966],"ol",{},[272,273,274,278,281,282],"li",{},[275,276,277],"strong",{},"Create a dedicated production config class",[279,280],"br",{},"Add a config module with explicit production settings:",[26,283,285],{"className":202,"code":284,"language":204,"meta":31,"style":31},"# config.py\nimport os\nfrom datetime import timedelta\n\nclass ProductionConfig:\n    DEBUG = False\n    TESTING = False\n\n    SECRET_KEY = os.environ['SECRET_KEY']\n    SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']\n    SQLALCHEMY_TRACK_MODIFICATIONS = False\n\n    SESSION_COOKIE_SECURE = True\n    SESSION_COOKIE_HTTPONLY = True\n    SESSION_COOKIE_SAMESITE = 'Lax'\n\n    PREFERRED_URL_SCHEME = 'https'\n    MAX_CONTENT_LENGTH = 16 * 1024 * 1024\n    PERMANENT_SESSION_LIFETIME = timedelta(hours=12)\n",[33,286,287,292,300,313,317,328,339,348,352,368,382,391,395,405,414,424,428,438,459],{"__ignoreMap":31},[36,288,289],{"class":38,"line":39},[36,290,291],{"class":42},"# config.py\n",[36,293,294,297],{"class":38,"line":46},[36,295,296],{"class":49},"import",[36,298,299],{"class":53}," os\n",[36,301,302,305,308,310],{"class":38,"line":63},[36,303,304],{"class":49},"from",[36,306,307],{"class":53}," datetime ",[36,309,296],{"class":49},[36,311,312],{"class":53}," timedelta\n",[36,314,315],{"class":38,"line":77},[36,316,94],{"emptyLinePlaceholder":93},[36,318,319,322,325],{"class":38,"line":90},[36,320,321],{"class":49},"class",[36,323,324],{"class":106}," ProductionConfig",[36,326,327],{"class":53},":\n",[36,329,330,333,336],{"class":38,"line":97},[36,331,332],{"class":237},"    DEBUG",[36,334,335],{"class":49}," =",[36,337,338],{"class":237}," False\n",[36,340,341,344,346],{"class":38,"line":103},[36,342,343],{"class":237},"    TESTING",[36,345,335],{"class":49},[36,347,338],{"class":237},[36,349,350],{"class":38,"line":122},[36,351,94],{"emptyLinePlaceholder":93},[36,353,354,357,359,362,365],{"class":38,"line":128},[36,355,356],{"class":237},"    SECRET_KEY",[36,358,335],{"class":49},[36,360,361],{"class":53}," os.environ[",[36,363,364],{"class":73},"'SECRET_KEY'",[36,366,367],{"class":53},"]\n",[36,369,370,373,375,377,380],{"class":38,"line":133},[36,371,372],{"class":237},"    SQLALCHEMY_DATABASE_URI",[36,374,335],{"class":49},[36,376,361],{"class":53},[36,378,379],{"class":73},"'DATABASE_URL'",[36,381,367],{"class":53},[36,383,384,387,389],{"class":38,"line":139},[36,385,386],{"class":237},"    SQLALCHEMY_TRACK_MODIFICATIONS",[36,388,335],{"class":49},[36,390,338],{"class":237},[36,392,393],{"class":38,"line":145},[36,394,94],{"emptyLinePlaceholder":93},[36,396,397,400,402],{"class":38,"line":151},[36,398,399],{"class":237},"    SESSION_COOKIE_SECURE",[36,401,335],{"class":49},[36,403,404],{"class":237}," True\n",[36,406,407,410,412],{"class":38,"line":157},[36,408,409],{"class":237},"    SESSION_COOKIE_HTTPONLY",[36,411,335],{"class":49},[36,413,404],{"class":237},[36,415,416,419,421],{"class":38,"line":163},[36,417,418],{"class":237},"    SESSION_COOKIE_SAMESITE",[36,420,335],{"class":49},[36,422,423],{"class":73}," 'Lax'\n",[36,425,426],{"class":38,"line":169},[36,427,94],{"emptyLinePlaceholder":93},[36,429,430,433,435],{"class":38,"line":175},[36,431,432],{"class":237},"    PREFERRED_URL_SCHEME",[36,434,335],{"class":49},[36,436,437],{"class":73}," 'https'\n",[36,439,440,443,445,448,451,454,456],{"class":38,"line":181},[36,441,442],{"class":237},"    MAX_CONTENT_LENGTH",[36,444,335],{"class":49},[36,446,447],{"class":237}," 16",[36,449,450],{"class":49}," *",[36,452,453],{"class":237}," 1024",[36,455,450],{"class":49},[36,457,458],{"class":237}," 1024\n",[36,460,461,464,466,469,473,475,478],{"class":38,"line":187},[36,462,463],{"class":237},"    PERMANENT_SESSION_LIFETIME",[36,465,335],{"class":49},[36,467,468],{"class":53}," timedelta(",[36,470,472],{"class":471},"s4XuR","hours",[36,474,57],{"class":49},[36,476,477],{"class":237},"12",[36,479,217],{"class":53},[272,481,482,485,487,488,514,516,517],{},[275,483,484],{},"Move secrets and environment-specific settings out of source code",[279,486],{},"Do not hardcode secrets, credentials, or production URLs.",[26,489,491],{"className":28,"code":490,"language":30,"meta":31,"style":31},"export SECRET_KEY='replace-with-a-random-value'\nexport DATABASE_URL='postgresql:\u002F\u002Fuser:pass@127.0.0.1:5432\u002Fappdb'\n",[33,492,493,504],{"__ignoreMap":31},[36,494,495,497,499,501],{"class":38,"line":39},[36,496,50],{"class":49},[36,498,68],{"class":53},[36,500,57],{"class":49},[36,502,503],{"class":73},"'replace-with-a-random-value'\n",[36,505,506,508,510,512],{"class":38,"line":46},[36,507,50],{"class":49},[36,509,82],{"class":53},[36,511,57],{"class":49},[36,513,87],{"class":73},[279,515],{},"Typical values to externalize:",[518,519,520,525,530,533,536],"ul",{},[272,521,522],{},[33,523,524],{},"SECRET_KEY",[272,526,527],{},[33,528,529],{},"DATABASE_URL",[272,531,532],{},"mail credentials",[272,534,535],{},"third-party API keys",[272,537,538],{},"storage credentials",[272,540,541,544,546,547],{},[275,542,543],{},"Load the production config explicitly in the app factory",[279,545],{},"Example app factory:",[26,548,550],{"className":202,"code":549,"language":204,"meta":31,"style":31},"# app\u002F__init__.py\nfrom flask import Flask\n\ndef create_app():\n    app = Flask(__name__)\n    app.config.from_object('config.ProductionConfig')\n\n    @app.get(\"\u002Fhealth\")\n    def health():\n        return {\"status\": \"ok\"}, 200\n\n    return app\n",[33,551,552,557,569,573,584,599,608,612,625,635,658,662],{"__ignoreMap":31},[36,553,554],{"class":38,"line":39},[36,555,556],{"class":42},"# app\u002F__init__.py\n",[36,558,559,561,564,566],{"class":38,"line":46},[36,560,304],{"class":49},[36,562,563],{"class":53}," flask ",[36,565,296],{"class":49},[36,567,568],{"class":53}," Flask\n",[36,570,571],{"class":38,"line":63},[36,572,94],{"emptyLinePlaceholder":93},[36,574,575,578,581],{"class":38,"line":77},[36,576,577],{"class":49},"def",[36,579,580],{"class":106}," create_app",[36,582,583],{"class":53},"():\n",[36,585,586,589,591,594,597],{"class":38,"line":90},[36,587,588],{"class":53},"    app ",[36,590,57],{"class":49},[36,592,593],{"class":53}," Flask(",[36,595,596],{"class":237},"__name__",[36,598,217],{"class":53},[36,600,601,604,606],{"class":38,"line":97},[36,602,603],{"class":53},"    app.config.from_object(",[36,605,214],{"class":73},[36,607,217],{"class":53},[36,609,610],{"class":38,"line":103},[36,611,94],{"emptyLinePlaceholder":93},[36,613,614,617,620,623],{"class":38,"line":122},[36,615,616],{"class":106},"    @app.get",[36,618,619],{"class":53},"(",[36,621,622],{"class":73},"\"\u002Fhealth\"",[36,624,217],{"class":53},[36,626,627,630,633],{"class":38,"line":128},[36,628,629],{"class":49},"    def",[36,631,632],{"class":106}," health",[36,634,583],{"class":53},[36,636,637,640,643,646,649,652,655],{"class":38,"line":133},[36,638,639],{"class":49},"        return",[36,641,642],{"class":53}," {",[36,644,645],{"class":73},"\"status\"",[36,647,648],{"class":53},": ",[36,650,651],{"class":73},"\"ok\"",[36,653,654],{"class":53},"}, ",[36,656,657],{"class":237},"200\n",[36,659,660],{"class":38,"line":139},[36,661,94],{"emptyLinePlaceholder":93},[36,663,664,667],{"class":38,"line":145},[36,665,666],{"class":49},"    return",[36,668,669],{"class":53}," app\n",[272,671,672,675,677,678],{},[275,673,674],{},"Create a WSGI entry point",[279,676],{},"Gunicorn should import a stable application object.",[26,679,681],{"className":202,"code":680,"language":204,"meta":31,"style":31},"# wsgi.py\nfrom app import create_app\n\napp = create_app()\n",[33,682,683,688,700,704],{"__ignoreMap":31},[36,684,685],{"class":38,"line":39},[36,686,687],{"class":42},"# wsgi.py\n",[36,689,690,692,695,697],{"class":38,"line":46},[36,691,304],{"class":49},[36,693,694],{"class":53}," app ",[36,696,296],{"class":49},[36,698,699],{"class":53}," create_app\n",[36,701,702],{"class":38,"line":63},[36,703,94],{"emptyLinePlaceholder":93},[36,705,706,709,711],{"class":38,"line":77},[36,707,708],{"class":53},"app ",[36,710,57],{"class":49},[36,712,713],{"class":53}," create_app()\n",[272,715,716,719,721,722,754,756,757,760],{},[275,717,718],{},"Set secure cookie behavior",[279,720],{},"For HTTPS deployments, keep cookies restricted:",[26,723,725],{"className":202,"code":724,"language":204,"meta":31,"style":31},"SESSION_COOKIE_SECURE = True\nSESSION_COOKIE_HTTPONLY = True\nSESSION_COOKIE_SAMESITE = 'Lax'\n",[33,726,727,736,745],{"__ignoreMap":31},[36,728,729,732,734],{"class":38,"line":39},[36,730,731],{"class":237},"SESSION_COOKIE_SECURE",[36,733,335],{"class":49},[36,735,404],{"class":237},[36,737,738,741,743],{"class":38,"line":46},[36,739,740],{"class":237},"SESSION_COOKIE_HTTPONLY",[36,742,335],{"class":49},[36,744,404],{"class":237},[36,746,747,750,752],{"class":38,"line":63},[36,748,749],{"class":237},"SESSION_COOKIE_SAMESITE",[36,751,335],{"class":49},[36,753,423],{"class":73},[279,755],{},"Use ",[33,758,759],{},"'Strict'"," only if your login and cross-site flows allow it.",[272,762,763,766,768,769,771,772,788,790],{},[275,764,765],{},"Use a production database",[279,767],{},"Replace SQLite with PostgreSQL or another production database for deployed multi-user applications.",[279,770],{},"Example:",[26,773,775],{"className":28,"code":774,"language":30,"meta":31,"style":31},"export DATABASE_URL='postgresql:\u002F\u002Fappuser:strongpassword@127.0.0.1:5432\u002Fappdb'\n",[33,776,777],{"__ignoreMap":31},[36,778,779,781,783,785],{"class":38,"line":39},[36,780,50],{"class":49},[36,782,82],{"class":53},[36,784,57],{"class":49},[36,786,787],{"class":73},"'postgresql:\u002F\u002Fappuser:strongpassword@127.0.0.1:5432\u002Fappdb'\n",[279,789],{},"If you are still using SQLite from development, replace it before traffic increases.",[272,792,793,800,802,803,805,806,809,810],{},[275,794,795,796,799],{},"Avoid ",[33,797,798],{},".env","-only production loading",[279,801],{},"For production, prefer runtime-managed environment injection.",[279,804],{},"Example ",[33,807,808],{},"systemd"," service:",[26,811,815],{"className":812,"code":813,"language":814,"meta":31,"style":31},"language-ini shiki shiki-themes github-light github-dark","[Unit]\nDescription=Gunicorn for Flask app\nAfter=network.target\n\n[Service]\nUser=www-data\nGroup=www-data\nWorkingDirectory=\u002Fsrv\u002Fyourapp\nEnvironment=\"SECRET_KEY=replace-with-real-secret\"\nEnvironment=\"DATABASE_URL=postgresql:\u002F\u002Fappuser:strongpassword@127.0.0.1:5432\u002Fappdb\"\nExecStart=\u002Fsrv\u002Fyourapp\u002Fvenv\u002Fbin\u002Fgunicorn -w 3 -b 127.0.0.1:8000 wsgi:app\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n","ini",[33,816,817,822,827,832,836,841,846,851,856,861,866,871,876,880,885],{"__ignoreMap":31},[36,818,819],{"class":38,"line":39},[36,820,821],{},"[Unit]\n",[36,823,824],{"class":38,"line":46},[36,825,826],{},"Description=Gunicorn for Flask app\n",[36,828,829],{"class":38,"line":63},[36,830,831],{},"After=network.target\n",[36,833,834],{"class":38,"line":77},[36,835,94],{"emptyLinePlaceholder":93},[36,837,838],{"class":38,"line":90},[36,839,840],{},"[Service]\n",[36,842,843],{"class":38,"line":97},[36,844,845],{},"User=www-data\n",[36,847,848],{"class":38,"line":103},[36,849,850],{},"Group=www-data\n",[36,852,853],{"class":38,"line":122},[36,854,855],{},"WorkingDirectory=\u002Fsrv\u002Fyourapp\n",[36,857,858],{"class":38,"line":128},[36,859,860],{},"Environment=\"SECRET_KEY=replace-with-real-secret\"\n",[36,862,863],{"class":38,"line":133},[36,864,865],{},"Environment=\"DATABASE_URL=postgresql:\u002F\u002Fappuser:strongpassword@127.0.0.1:5432\u002Fappdb\"\n",[36,867,868],{"class":38,"line":139},[36,869,870],{},"ExecStart=\u002Fsrv\u002Fyourapp\u002Fvenv\u002Fbin\u002Fgunicorn -w 3 -b 127.0.0.1:8000 wsgi:app\n",[36,872,873],{"class":38,"line":145},[36,874,875],{},"Restart=always\n",[36,877,878],{"class":38,"line":151},[36,879,94],{"emptyLinePlaceholder":93},[36,881,882],{"class":38,"line":157},[36,883,884],{},"[Install]\n",[36,886,887],{"class":38,"line":163},[36,888,889],{},"WantedBy=multi-user.target\n",[272,891,892,895,897,898,916,918,919,924],{},[275,893,894],{},"Run the app with Gunicorn",[279,896],{},"Start the app behind a real WSGI server:",[26,899,900],{"className":28,"code":227,"language":30,"meta":31,"style":31},[33,901,902],{"__ignoreMap":31},[36,903,904,906,908,910,912,914],{"class":38,"line":39},[36,905,234],{"class":106},[36,907,238],{"class":237},[36,909,241],{"class":237},[36,911,244],{"class":237},[36,913,247],{"class":73},[36,915,250],{"class":73},[279,917],{},"For a full reverse-proxy deployment, continue with ",[920,921,923],"a",{"href":922},"\u002Fdeploy\u002Fdeploy-flask-with-nginx-plus-gunicorn-step-by-step-guide","Deploy Flask with Nginx + Gunicorn (Step-by-Step Guide)",".",[272,926,927,930,932,933,948,950,951],{},[275,928,929],{},"Validate that Flask loaded the correct config",[279,931],{},"Confirm values from the actual runtime:",[26,934,936],{"className":28,"code":935,"language":30,"meta":31,"style":31},"python -c \"from app import create_app; app=create_app(); print('DEBUG=', app.config.get('DEBUG')); print('DB=', app.config.get('SQLALCHEMY_DATABASE_URI')); print('COOKIE_SECURE=', app.config.get('SESSION_COOKIE_SECURE'))\"\n",[33,937,938],{"__ignoreMap":31},[36,939,940,942,945],{"class":38,"line":39},[36,941,204],{"class":106},[36,943,944],{"class":237}," -c",[36,946,947],{"class":73}," \"from app import create_app; app=create_app(); print('DEBUG=', app.config.get('DEBUG')); print('DB=', app.config.get('SQLALCHEMY_DATABASE_URI')); print('COOKIE_SECURE=', app.config.get('SESSION_COOKIE_SECURE'))\"\n",[279,949],{},"Expected output:",[518,952,953,958,961],{},[272,954,955],{},[33,956,957],{},"DEBUG= False",[272,959,960],{},"production database URL present",[272,962,963],{},[33,964,965],{},"COOKIE_SECURE= True",[272,967,968],{},[275,969,970],{},"Restart the service after config changes",[14,972,973,974,224],{},"If using ",[33,975,808],{},[26,977,979],{"className":28,"code":978,"language":30,"meta":31,"style":31},"sudo systemctl daemon-reload\nsudo systemctl restart yourapp\nsudo systemctl status yourapp --no-pager\n",[33,980,981,992,1004],{"__ignoreMap":31},[36,982,983,986,989],{"class":38,"line":39},[36,984,985],{"class":106},"sudo",[36,987,988],{"class":73}," systemctl",[36,990,991],{"class":73}," daemon-reload\n",[36,993,994,996,998,1001],{"class":38,"line":46},[36,995,985],{"class":106},[36,997,988],{"class":73},[36,999,1000],{"class":73}," restart",[36,1002,1003],{"class":73}," yourapp\n",[36,1005,1006,1008,1010,1013,1016],{"class":38,"line":63},[36,1007,985],{"class":106},[36,1009,988],{"class":73},[36,1011,1012],{"class":73}," status",[36,1014,1015],{"class":73}," yourapp",[36,1017,1018],{"class":237}," --no-pager\n",[269,1020,1021],{"start":139},[272,1022,1023],{},[275,1024,1025],{},"Verify response locally and through the proxy",[14,1027,1028],{},"Check Gunicorn directly:",[26,1030,1032],{"className":28,"code":1031,"language":30,"meta":31,"style":31},"curl -I http:\u002F\u002F127.0.0.1:8000\n",[33,1033,1034],{"__ignoreMap":31},[36,1035,1036,1039,1042],{"class":38,"line":39},[36,1037,1038],{"class":106},"curl",[36,1040,1041],{"class":237}," -I",[36,1043,1044],{"class":73}," http:\u002F\u002F127.0.0.1:8000\n",[14,1046,1047],{},"Check through the public endpoint:",[26,1049,1051],{"className":28,"code":1050,"language":30,"meta":31,"style":31},"curl -I https:\u002F\u002Fyourdomain.com\n",[33,1052,1053],{"__ignoreMap":31},[36,1054,1055,1057,1059],{"class":38,"line":39},[36,1056,1038],{"class":106},[36,1058,1041],{"class":237},[36,1060,1061],{"class":73}," https:\u002F\u002Fyourdomain.com\n",[269,1063,1064],{"start":145},[272,1065,1066],{},[275,1067,1068],{},"Confirm HTTPS and proxy behavior",[14,1070,1071,1072,1075,1076,924],{},"If Flask generates ",[33,1073,1074],{},"http:\u002F\u002F"," URLs behind Nginx, your proxy headers are incomplete. Validate your reverse proxy setup in ",[920,1077,923],{"href":922},[18,1079,1081],{"id":1080},"common-causes","Common Causes",[518,1083,1084,1094,1100,1106,1116,1125,1131],{},[272,1085,1086,1089,1090,1093],{},[275,1087,1088],{},"DEBUG=True in production"," → exposes development behavior and can create security risk → set ",[33,1091,1092],{},"DEBUG = False"," in the production config and stop using dev-only startup commands.",[272,1095,1096,1099],{},[275,1097,1098],{},"SECRET_KEY missing or hardcoded"," → sessions fail or secrets leak into source control → load it from environment variables.",[272,1101,1102,1105],{},[275,1103,1104],{},"DATABASE_URL unset or invalid"," → app crashes at startup or fails on first database access → define and validate the production database URL.",[272,1107,1108,1111,1112,1115],{},[275,1109,1110],{},"Environment variables not available to systemd or Gunicorn"," → config works in your shell but not in the service → define ",[33,1113,1114],{},"Environment="," or use a dedicated env file in the service definition.",[272,1117,1118,1124],{},[275,1119,1120,1121,1123],{},"Using ",[33,1122,223],{}," instead of Gunicorn"," → weak process management and poor production behavior → run Gunicorn behind Nginx.",[272,1126,1127,1130],{},[275,1128,1129],{},"HTTPS-related settings incomplete"," → incorrect redirects or insecure cookies → enable secure cookie settings and pass correct proxy headers.",[272,1132,1133,1136],{},[275,1134,1135],{},"SQLite retained from development"," → file locking and reliability issues under concurrent traffic → migrate to PostgreSQL.",[18,1138,1140],{"id":1139},"debugging-section","Debugging Section",[14,1142,1143],{},"Check environment visibility:",[26,1145,1147],{"className":28,"code":1146,"language":30,"meta":31,"style":31},"env | sort | egrep 'FLASK|SECRET_KEY|DATABASE_URL'\n",[33,1148,1149],{"__ignoreMap":31},[36,1150,1151,1154,1157,1160,1162,1165],{"class":38,"line":39},[36,1152,1153],{"class":106},"env",[36,1155,1156],{"class":49}," |",[36,1158,1159],{"class":106}," sort",[36,1161,1156],{"class":49},[36,1163,1164],{"class":106}," egrep",[36,1166,1167],{"class":73}," 'FLASK|SECRET_KEY|DATABASE_URL'\n",[14,1169,1170],{},"Inspect effective Flask config:",[26,1172,1173],{"className":28,"code":935,"language":30,"meta":31,"style":31},[33,1174,1175],{"__ignoreMap":31},[36,1176,1177,1179,1181],{"class":38,"line":39},[36,1178,204],{"class":106},[36,1180,944],{"class":237},[36,1182,947],{"class":73},[14,1184,1185],{},"Run Gunicorn with verbose startup logs:",[26,1187,1189],{"className":28,"code":1188,"language":30,"meta":31,"style":31},"gunicorn -w 3 -b 127.0.0.1:8000 'wsgi:app' --log-level debug\n",[33,1190,1191],{"__ignoreMap":31},[36,1192,1193,1195,1197,1199,1201,1203,1206,1209],{"class":38,"line":39},[36,1194,234],{"class":106},[36,1196,238],{"class":237},[36,1198,241],{"class":237},[36,1200,244],{"class":237},[36,1202,247],{"class":73},[36,1204,1205],{"class":73}," 'wsgi:app'",[36,1207,1208],{"class":237}," --log-level",[36,1210,1211],{"class":73}," debug\n",[14,1213,1214,1215,1217],{},"Inspect ",[33,1216,808],{}," service configuration:",[26,1219,1221],{"className":28,"code":1220,"language":30,"meta":31,"style":31},"systemctl cat yourapp\nsystemctl show yourapp --property=Environment\njournalctl -u yourapp -n 100 --no-pager\n",[33,1222,1223,1233,1245],{"__ignoreMap":31},[36,1224,1225,1228,1231],{"class":38,"line":39},[36,1226,1227],{"class":106},"systemctl",[36,1229,1230],{"class":73}," cat",[36,1232,1003],{"class":73},[36,1234,1235,1237,1240,1242],{"class":38,"line":46},[36,1236,1227],{"class":106},[36,1238,1239],{"class":73}," show",[36,1241,1015],{"class":73},[36,1243,1244],{"class":237}," --property=Environment\n",[36,1246,1247,1250,1253,1255,1258,1261],{"class":38,"line":63},[36,1248,1249],{"class":106},"journalctl",[36,1251,1252],{"class":237}," -u",[36,1254,1015],{"class":73},[36,1256,1257],{"class":237}," -n",[36,1259,1260],{"class":237}," 100",[36,1262,1018],{"class":237},[14,1264,1265],{},"Validate Nginx syntax:",[26,1267,1269],{"className":28,"code":1268,"language":30,"meta":31,"style":31},"sudo nginx -t\n",[33,1270,1271],{"__ignoreMap":31},[36,1272,1273,1275,1278],{"class":38,"line":39},[36,1274,985],{"class":106},[36,1276,1277],{"class":73}," nginx",[36,1279,1280],{"class":237}," -t\n",[14,1282,1283],{},"Test app reachability:",[26,1285,1287],{"className":28,"code":1286,"language":30,"meta":31,"style":31},"curl -I http:\u002F\u002F127.0.0.1:8000\ncurl -I https:\u002F\u002Fyourdomain.com\n",[33,1288,1289,1297],{"__ignoreMap":31},[36,1290,1291,1293,1295],{"class":38,"line":39},[36,1292,1038],{"class":106},[36,1294,1041],{"class":237},[36,1296,1044],{"class":73},[36,1298,1299,1301,1303],{"class":38,"line":46},[36,1300,1038],{"class":106},[36,1302,1041],{"class":237},[36,1304,1061],{"class":73},[14,1306,1307],{},"Check whether the service process can see required variables:",[26,1309,1311],{"className":28,"code":1310,"language":30,"meta":31,"style":31},"python -c \"import os; print(os.environ.get('SECRET_KEY')); print(os.environ.get('DATABASE_URL'))\"\n",[33,1312,1313],{"__ignoreMap":31},[36,1314,1315,1317,1319],{"class":38,"line":39},[36,1316,204],{"class":106},[36,1318,944],{"class":237},[36,1320,1321],{"class":73}," \"import os; print(os.environ.get('SECRET_KEY')); print(os.environ.get('DATABASE_URL'))\"\n",[14,1323,1324],{},"What to look for:",[518,1326,1327,1332,1337,1342,1345,1348],{},[272,1328,1329,1330],{},"missing ",[33,1331,524],{},[272,1333,1334,1335],{},"empty or malformed ",[33,1336,529],{},[272,1338,1339],{},[33,1340,1341],{},"DEBUG=True",[272,1343,1344],{},"Gunicorn import errors",[272,1346,1347],{},"Nginx proxy or TLS misconfiguration",[272,1349,1350,1352],{},[33,1351,808],{}," service running with a different working directory or virtualenv",[18,1354,1356],{"id":1355},"checklist","Checklist",[518,1358,1361,1374,1382,1390,1396,1405,1413,1419,1425,1431,1437],{"className":1359},[1360],"contains-task-list",[272,1362,1365,1369,1370,1373],{"className":1363},[1364],"task-list-item",[1366,1367],"input",{"disabled":93,"type":1368},"checkbox"," ",[33,1371,1372],{},"DEBUG"," is disabled in production.",[272,1375,1377,1369,1379,1373],{"className":1376},[1364],[1366,1378],{"disabled":93,"type":1368},[33,1380,1381],{},"TESTING",[272,1383,1385,1369,1387,1389],{"className":1384},[1364],[1366,1386],{"disabled":93,"type":1368},[33,1388,524],{}," is loaded from an environment variable.",[272,1391,1393,1395],{"className":1392},[1364],[1366,1394],{"disabled":93,"type":1368}," Database configuration uses a production database URL.",[272,1397,1399,1369,1401,1404],{"className":1398},[1364],[1366,1400],{"disabled":93,"type":1368},[33,1402,1403],{},"SQLALCHEMY_TRACK_MODIFICATIONS"," is disabled if using Flask-SQLAlchemy.",[272,1406,1408,1410,1411,924],{"className":1407},[1364],[1366,1409],{"disabled":93,"type":1368}," Gunicorn is used instead of ",[33,1412,223],{},[272,1414,1416,1418],{"className":1415},[1364],[1366,1417],{"disabled":93,"type":1368}," Secure cookie settings are enabled for HTTPS deployments.",[272,1420,1422,1424],{"className":1421},[1364],[1366,1423],{"disabled":93,"type":1368}," Production config is loaded explicitly by the app.",[272,1426,1428,1430],{"className":1427},[1364],[1366,1429],{"disabled":93,"type":1368}," Environment variables are available to the runtime process.",[272,1432,1434,1436],{"className":1433},[1364],[1366,1435],{"disabled":93,"type":1368}," The app restarts cleanly after config changes.",[272,1438,1440,1442],{"className":1439},[1364],[1366,1441],{"disabled":93,"type":1368}," Requests work through Nginx without debug pages or scheme issues.",[18,1444,1446],{"id":1445},"related-guides","Related Guides",[518,1448,1449,1453,1459],{},[272,1450,1451],{},[920,1452,923],{"href":922},[272,1454,1455],{},[920,1456,1458],{"href":1457},"\u002Fdeploy\u002Fflask-environment-variables-and-secrets-setup","Flask Environment Variables and Secrets Setup",[272,1460,1461],{},[920,1462,1464],{"href":1463},"\u002Fchecklist\u002Fflask-production-checklist-everything-you-must-do","Flask Production Checklist (Everything You Must Do)",[18,1466,1468],{"id":1467},"faq","FAQ",[1470,1471,1473],"h3",{"id":1472},"what-is-the-minimum-production-config-for-flask","What is the minimum production config for Flask?",[14,1475,1476,1477,1479,1480,1482,1483,1485],{},"Disable ",[33,1478,1372],{}," and ",[33,1481,1381],{},", load ",[33,1484,524],{}," and database settings from environment variables, enable secure cookie settings, and run behind Gunicorn.",[1470,1487,1489],{"id":1488},"should-configuration-live-in-code-or-environment-variables","Should configuration live in code or environment variables?",[14,1491,1492],{},"Keep non-secret defaults in code and inject secrets or environment-specific values at runtime.",[1470,1494,1496,1497,1499],{"id":1495},"can-i-use-flask-run-in-production","Can I use ",[33,1498,223],{}," in production?",[14,1501,1502],{},"No. Use Gunicorn or another production WSGI server.",[1470,1504,1506],{"id":1505},"why-are-my-environment-variables-missing-only-in-production","Why are my environment variables missing only in production?",[14,1508,1509,1510,1512],{},"Your process manager may not load the same shell environment. Define variables in ",[33,1511,808],{},", Docker, or your hosting runtime.",[1470,1514,1516],{"id":1515},"do-i-need-a-separate-config-class-for-each-environment","Do I need a separate config class for each environment?",[14,1518,1519],{},"Yes. Separate development, staging, and production settings to avoid accidental cross-environment behavior.",[18,1521,1523],{"id":1522},"final-takeaway","Final Takeaway",[14,1525,1526],{},"Production Flask config should be explicit, environment-driven, and safe by default. If you disable debug mode, externalize secrets, use Gunicorn, and verify runtime environment loading, most deployment configuration problems are avoided before deployment.",[1528,1529,1530],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":31,"searchDepth":46,"depth":46,"links":1532},[1533,1534,1535,1536,1537,1538,1539,1540,1548],{"id":20,"depth":46,"text":21},{"id":256,"depth":46,"text":257},{"id":266,"depth":46,"text":267},{"id":1080,"depth":46,"text":1081},{"id":1139,"depth":46,"text":1140},{"id":1355,"depth":46,"text":1356},{"id":1445,"depth":46,"text":1446},{"id":1467,"depth":46,"text":1468,"children":1541},[1542,1543,1544,1546,1547],{"id":1472,"depth":63,"text":1473},{"id":1488,"depth":63,"text":1489},{"id":1495,"depth":63,"text":1545},"Can I use flask run in production?",{"id":1505,"depth":63,"text":1506},{"id":1515,"depth":63,"text":1516},{"id":1522,"depth":46,"text":1523},"Complete guide on flask production config basics for Flask production environments.","md",{"ogTitle":5,"ogDescription":1549,"twitterCard":1552,"robots":1553,"canonical":1554},"summary_large_image","index, follow","https:\u002F\u002Fflask-deployment.com\u002Fdeploy\u002Fflask-production-config-basics","\u002Fdeploy\u002Fflask-production-config-basics",{"title":5,"description":1549},"deploy\u002Fflask-production-config-basics","6fB7zOUJ_NYPOTeNCuYpmv2CmFnwTwdK3Gr-BmbzgXM",1776805765880]