Production Environment Considerations
Relevant source files
The following files were used as context for generating this wiki page:The Becathlon application is designed for deployment on the PWS (Proyek Web Lanjut) platform, which influences its production configuration. This document outlines the key considerations for deploying and maintaining the application in a production environment, focusing on configuration, deployment scripts, static file handling, and database management. The system relies heavily on environment variables to differentiate between development and production modes, particularly for database connections and security settings.
The production setup utilizes a PostgreSQL database and the WhiteNoise library for efficient static file serving. A deployment script automates the collection of static assets and database migrations. Additionally, a specific script is available for completely resetting the production database, which should be used with extreme caution.
Deployment Process
The deployment to the PWS environment is managed by the pbp-deploy.sh script. This script automates the necessary steps to prepare the application for serving traffic after the code has been updated.
Sources: pbp-deploy.sh
The following diagram illustrates the automated deployment flow executed by the script.
Sources: pbp-deploy.sh:7-17
The key steps are:
- Directory Creation: Ensures that the target directories for static and media files (
/tmp/staticfilesand/tmp/media) exist on the deployment server. - Static File Collection: Executes the Django management command
collectstatic. The--noinputflag prevents prompts, and--clearremoves old files before collecting new ones. This process gathers all static assets from the various Django apps into theSTATIC_ROOTdirectory. - Database Migration: Runs
migrateto apply any new database schema changes. The--noinputflag automates this step.
Sources: pbp-deploy.sh
Configuration
Production configuration is primarily managed within becathlon/settings.py and is heavily influenced by environment variables. This allows for a flexible setup that can easily switch between development (SQLite) and production (PostgreSQL) environments.
Sources: becathlon/settings.py
Environment Variables
The application's behavior in production is controlled by several environment variables. If these are not set, the application falls back to development-friendly defaults.
| Variable | Purpose | Default / Fallback |
|---|---|---|
SECRET_KEY | Django's secret key for cryptographic signing. | A default insecure key. |
DEBUG | Toggles Django's debug mode. | 'True' |
ALLOWED_HOSTS | A comma-separated list of allowed hostnames. | 'localhost,127.0.0.1,testserver' |
DB_NAME | The name of the PostgreSQL database. | None (triggers SQLite fallback) |
DB_USER | The PostgreSQL database user. | None |
DB_PASSWORD | The password for the PostgreSQL user. | None |
DB_HOST | The hostname of the database server. | None |
DB_PORT | The port for the database server. | '5432' |
SCHEMA | The PostgreSQL schema to use. | None |
STATIC_URL | The URL to serve static files from. | '/static/' |
STATIC_ROOT | The absolute path to the directory where collectstatic will collect static files. | BASE_DIR / 'staticfiles' |
MEDIA_URL | The URL that handles media served from MEDIA_ROOT. | '/media/' |
MEDIA_ROOT | The absolute path to the directory that will hold user-uploaded files. | BASE_DIR / 'media' |
Sources: becathlon/settings.py:23-32, 110-117, 185-186, 196-197
Database Configuration
The project dynamically configures its database connection based on the presence of PostgreSQL environment variables. If they are set, it connects to a PostgreSQL database; otherwise, it defaults to a local SQLite file.
This diagram shows the conditional logic for database setup.
Sources: becathlon/settings.py:110-141
The PostgreSQL configuration for production includes specific options:
# becathlon/settings.py:120-134
db_config = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': DB_NAME,
'USER': DB_USER,
'PASSWORD': DB_PASSWORD,
'HOST': DB_HOST,
'PORT': DB_PORT or '5432',
'ATOMIC_REQUESTS': False,
'CONN_MAX_AGE': 0,
}
if DB_SCHEMA:
db_config['OPTIONS'] = {
'options': f'-c search_path={DB_SCHEMA},public'
}
ATOMIC_REQUESTSis set toFalseto allow for non-atomic operations, which can be useful for complex migrations.CONN_MAX_AGEis0, causing database connections to be closed immediately after each request.- If a
SCHEMAis provided, it's added to thesearch_pathto ensure the correct tables are accessed.
Sources: becathlon/settings.py:110-141
Security Settings
When DEBUG is False, several security enhancements are activated to protect the application in production.
| Setting | Value | Purpose |
|---|---|---|
SECURE_SSL_REDIRECT | False | Disabled because PWS handles SSL termination. |
SESSION_COOKIE_SECURE | True | Ensures session cookies are only sent over HTTPS. |
CSRF_COOKIE_SECURE | True | Ensures CSRF cookies are only sent over HTTPS. |
SECURE_BROWSER_XSS_FILTER | True | Enables the browser's built-in XSS protection. |
SECURE_CONTENT_TYPE_NOSNIFF | True | Prevents the browser from MIME-sniffing the content type. |
X_FRAME_OPTIONS | 'DENY' | Prevents the site from being rendered in an <iframe>. |
CSRF_COOKIE_SAMESITE | 'Lax' | Sets the SameSite attribute on the CSRF cookie. |
SESSION_COOKIE_SAMESITE | 'Lax' | Sets the SameSite attribute on the session cookie. |
Sources: becathlon/settings.py:41-54
Additionally, CSRF_TRUSTED_ORIGINS is configured to allow POST requests from the PWS deployment domains.
# becathlon/settings.py:35-39
CSRF_TRUSTED_ORIGINS = [
'https://muhammad-vegard-becathlon.pbp.cs.ui.ac.id',
'https://pbp.cs.ui.ac.id',
'https://muhammad.vegard.pbp.cs.ui.ac.id',
]
Sources: becathlon/settings.py:35-39, README.md:94
Static Asset Handling
In production, static files (CSS, JavaScript, images) are served using WhiteNoise, a library designed to serve static files directly from a Python web application without needing a separate web server like Nginx.
Sources: becathlon/settings.py:82, 178-184
Static File Collection and Serving Flow
- During development, static files are located within each app's
static/directory (e.g.,apps/catalog/static/catalog/js/catalog.js). - The
pbp-deploy.shscript runspython manage.py collectstatic. - This command copies all static files from the app directories into a single directory defined by
STATIC_ROOT(e.g.,staticfiles/). - The
WhiteNoiseMiddlewareintercepts requests for URLs underSTATIC_URL(e.g.,/static/). WhiteNoiseserves the corresponding file from theSTATIC_ROOTdirectory, applying compression and caching headers.
The following diagram shows this process.
The storage backend is configured to use whitenoise.storage.CompressedStaticFilesStorage, which creates compressed versions (Gzip, Brotli) of the static files during the collectstatic process.
# becathlon/settings.py:180-184
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedStaticFilesStorage",
},
}
Sources: becathlon/settings.py:180-184
Database Management
A utility script, reset_production_db.py, is provided for completely resetting the production PostgreSQL database. This is a destructive operation and will delete all data.
Sources: reset_production_db.py
Reset Script Workflow
The script is designed to be run manually and includes a safeguard to prevent accidental execution.
The sequence diagram below shows the interaction and steps involved in running the script.
Sources: reset_production_db.py:27-72
The script performs the following actions:
- Connects to the database specified in
settings.py. - Prompts the user for explicit confirmation to proceed.
- Executes a SQL query to get all table names in the current schema.
- Iterates through the tables and drops each one using
DROP TABLE ... CASCADE. - Calls
django.core.management.call_command('migrate')to recreate the database schema from scratch. - Executes
seed_product_types.pyto populate initial data.
Sources: reset_production_db.py:35-61