Deploying to the DigitalOcean App Platform - Using Docker Only for Local Development
This article explains how to deploy a web application using the DigitalOcean App Platform. For beginners in web development, one of the biggest hurdles to launching their own apps is deployment, and many struggle with this process even when following reliable tutorials.
I've been using DigitalOcean for 5–6 years. Initially, I used Droplets (VPS) for deployment. While Droplets are affordable, scalable, and flexible—making them ideal for individual developers—they aren't designed for simplified deployments. Configuring the web server and database from scratch can be quite tedious. I remember spending several days troubleshooting my first deployment with Droplets.
However, the release of DigitalOcean's App Platform in 2020 drastically simplified the deployment process. While the App Platform is slightly more expensive than Droplets, the ease of use more than justifies the cost.
This tutorial provides a stress-free and quick deployment method using the App Platform, ensuring that even those new to Django development can deploy their applications with ease. Although I use Docker in my development environment, deployment is even simpler without Docker, so we'll focus on that approach here.
Please note that this article contains affiliate links.
- Introducing the Repository I Created for this Deployment Tutorial
While deploying to the App Platform is much easier than deploying to other cloud servers, there are still a few potential pitfalls.
When you encounter these issues with a complex application, it's hard to tell whether the deployment failure stems from the application code itself or the deployment configuration.
To avoid this problem, it's best to use a simple application structure for experimental deployments.
For this reason, I've created a minimal application that displays "Hello World." If you don't have a suitable app for testing deployments, clone this repository and try deploying it to your DigitalOcean App Platform account.
Important: This repository has two branches: master and develop. Be sure to clone the develop branch.
For example, use the following command to clone the repository:
git clone -b develop --single-branch https://github.com/DevWoody856/minimal_django_app.git
The file structure of the repository is shown in the attached image. I'll explain the deployment process based on this structure.
2. The Settings Directory Structure
Properly structuring your settings is essential when deploying Django applications to production. While a single settings.py file is common during development, some settings shouldn't be pushed to production, while others require environment-specific configurations.
Therefore, instead of a single settings.py, we create a settings directory, splitting settings.py into multiple files within this directory. Only the necessary files are then pushed to production.
The settings folder contains:
settings/__init__.py: This file tells Python to treat the settings directory as a package. It also contains the logic to determine which settings file to load based on the current environment.
settings/base.py: This file houses common settings shared across all environments, such as INSTALLED_APPS, MIDDLEWARE, and TEMPLATES.
settings/dev.py: This file contains development-specific settings, like DEBUG = True, logging configurations, and any development tools or libraries.
settings/prod.py: This file holds production-specific settings, including database credentials, security configurations (e.g., ALLOWED_HOSTS), and optimization settings.
3. Writing Each File for Production Deployment
3-1. __init__.py
The __init__.py file dynamically loads the correct settings file based on the environment:
If the environment variable DJANGO_ENVIRONMENT is set to prod, the prod.py settings are loaded. Otherwise, dev.py is used.
You can set the DJANGO_ENVIRONMENT variable in the DigitalOcean App Platform control panel.
With this configuration, if DJANGO_ENVIRONMENT is prod, the production settings are imported on the App Platform. If it's any other value, the development settings are imported.
settings\__init__.py
import os
from pathlib import Path
if os.environ.get('DJANGO_ENVIRONMENT') == 'prod':
from .prod import *
else:
from .dev import *
3-2. prod.py
This is the production settings file. You will deploy this file to the DigitalOcean App Platform.
settings\prod.py
from .base import *
from urllib.parse import urlparse
DEBUG = False
BASE_DIR = Path(__file__).resolve().parent.parent.parent
ALLOWED_HOSTS = os.getenv("DJANGO_ALLOWED_HOSTS", "127.0.0.1,localhost").split(",")
DATABASE_URL = os.getenv('DATABASE_URL', None)
if not DATABASE_URL:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
else:
db_info = urlparse(DATABASE_URL)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'db',
'USER': db_info.username,
'PASSWORD': db_info.password,
'HOST': db_info.hostname,
'PORT': db_info.port,
'OPTIONS': {'sslmode': 'require'},
}
}
3-3. dev.py
This is the development settings file. This file should not be deployed to the DigitalOcean App Platform.
Therefore, you need to add its path to your .gitignore file.
After splitting the files as described above, let's review the other necessary files.
settings\dev.py
from .base import *
import environ
DEBUG = True
env = environ.Env()
BASE_DIR = Path(__file__).resolve().parent.parent.parent
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
ALLOWED_HOSTS = []
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
4. Reviewing Other Necessary Files
The following files are required for deployment:
requirements.txt: This file lists the packages to be installed. We're installing Django, psycopg2-binary, django-environ, and gunicorn.
requirements.txt
Django==5.1.2
psycopg2-binary==2.9.10
django-environ==0.11.2
gunicorn==23.0.0
Procfile: Tells the App Platform how to run your application.
While the App Platform may work without a Procfile, including it increases deployment reliability.
The Procfile should contain:
Procfile
web: gunicorn simple_app.wsgi
5. Development-Only Files (Exclude from Deployment)
The following files are for development only and should be excluded from deployment:
docker-compose.yaml: The App Platform doesn't support docker-compose.yaml, so exclude this file.
Dockerfile: While the App Platform does support deployments using a Dockerfile, doing so requires merging the configurations from your docker-compose.yaml into the Dockerfile. This adds extra configuration steps and complexity. For simplicity, I recommend avoiding Dockerfile deployments on the App Platform.
.env: Manually enter the .env variables into the App Platform's environment variable settings. The .env file itself isn't used directly.
old_settings.py: My repository includes old_settings.py, which is the original, unsplit settings.py file. This file isn't needed in the current configuration and should be excluded from deployment.
Configuring the .gitignore File
Ensure these four files are in your .gitignore:
docker-compose.yamlDockerfile.envold_settings.py
Including these files may cause deployment issues. See my .gitignore file for reference.
6. Pushing to Your GitHub Repository
Next, push your code to GitHub.
Note: I've set my deployment target branch to develop, not the default main branch. This distinction is important for the next step, so please keep it in mind.
7. Deploy Using the DigitalOcean App Platform
Once you've prepared your project for deployment, create a DigitalOcean account and deploy it to the App Platform.
While the standard App Platform deployment process is documented elsewhere, this guide explains the steps tailored to our setup.
Note: If you don't have a DigitalOcean account yet, sign up at DigitalOcean App Platform. They're currently offering $200 in free credits—plenty to get you started.
Deploying your application involves four main steps:
- Creating a DigitalOcean account and connecting your GitHub account
- Configuring the database
- Entering environment variables
- Deploying the application
Let's walk through these steps with screenshots.
7-1. Creating a DigitalOcean Account and Connecting Your GitHub Account
Creating a DigitalOcean account is straightforward, so I'll skip those details. Here's what to do after logging in:
7-1-1. Connecting Your GitHub Account
On the DigitalOcean dashboard, you'll see a green "Create" button in the header. Click it, and select "App Platform" from the menu.
You'll then see a screen similar to Image 1. Select "GitHub." If this is your first time, you'll need to grant DigitalOcean the necessary permissions on GitHub. Follow the on-screen instructions.
Once connected, you'll be able to select the repository you pushed your app to.
After selecting the repository, choose the branch you want to deploy.
7-1-2. Selecting a Web Server
Next, you'll configure your resources. This involves setting up the web server for your application and potentially a worker if you're using Celery.
You should see a screen like Image 2. Click "Edit," and Image 3 should appear.
The "Resource Type" should already be set to "Web Service," which is correct.
The important setting here is "Resource Size." The cheapest option is $5/month.
Select this option. (The prices displayed are monthly. If you destroy the app immediately after successful deployment, you likely won't be charged. Plus, remember the $200 free credit!)
7-2. Configuring the Database
After connecting to GitHub and configuring the web server, it's time to set up the database.
As shown in Image 5, you can select a database from the "Add Resource" section.
Select "Database" and click "Add." You'll be taken to a screen like Image 6.
Pay attention to the database name. For security reasons, you should change this name. However, if you do, you'll also need to modify the following section in your settings/prod.py file:
Failure to update this will result in deployment errors.
Finally, you'll see the database cost. A development database is $7/month, but you likely won't be charged much if you destroy the app shortly after deployment.
After configuring the database, you'll see a screen similar to Image 7.
settings\prod.py
db_info = urlparse(DATABASE_URL)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'db',
'USER': db_info.username,
'PASSWORD': db_info.password,
'HOST': db_info.hostname,
'PORT': db_info.port,
'OPTIONS': {'sslmode': 'require'},
}
}
7-3. Entering Environment Variables
Next, enter your environment variables. Click "Next" on Image 7 to proceed to Image 8.
You can set environment variables globally or per app. For security reasons, we'll set all variables at the app level.
Click "Edit" for your app to access the environment variable input screen shown in Image 9.
If you've already configured the database, the `DATABASE_URL` value will be pre-filled.
Because `DATABASE_URL` includes the USER, PASSWORD, HOST, and PORT values from your Django `prod.py` file, you don't need to set those individually as environment variables.
Besides `DATABASE_URL`, here are the other variables you need to set for this deployment:
**a. DJANGO_ENVIRONMENT:** This variable, used in the `__init__.py` file within your settings folder, determines which settings file is loaded. Set it to `prod` for production environments.
**b. SECRET_KEY:** Enter your Django secret key.
**c. DJANGO_ALLOWED_HOSTS:** Enter `${APP_DOMAIN}` here. This will automatically populate with the domain assigned by DigitalOcean. Even if you plan to use a custom domain, use `${APP_DOMAIN}` here. (Custom domain setup is beyond the scope of this tutorial, but there's a dedicated section for it in the App Platform settings. Setting `DJANGO_ALLOWED_HOSTS` to `${APP_DOMAIN}` will automatically configure your custom domain once you add it.)
For further information, see this [DigitalOcean article](https://docs.digitalocean.com/products/app-platform/getting-started/sample-apps/django/).
7-4. Deploying the Application
After completing steps 1-3, you'll see Image 10, which is a confirmation screen. Click "Next."
You'll then see Image 11, summarizing the final configuration and cost. With our minimal configuration, the monthly cost is $12.
However, combining the free $200 credit with destroying the app shortly after deployment should result in no charges.
Click "Create Resources" to begin deployment.
The deployment process will take a few minutes. Upon successful deployment, you'll see a green success message, as shown in the screenshot.
Next, select the "Console" tab and run the `migrate` and `createsuperuser` commands to initialize your app.
Conclusion
Deploying to the App Platform is quite straightforward, but there are a few key points to remember. Based on my experience with the App Platform, here are some tips for smooth deployments:
1. Include Gunicorn in requirements.txt: While Django's development server is sufficient during development, you need a WSGI server like Gunicorn in production to interface between the web server and your Python application. Without it, deployment will fail.
2. Create a Procfile: Without a Procfile, the App Platform might not know how to start your application, leading to errors. Creating a Procfile prevents this.
PaaS (Platform as a Service) has significantly simplified application deployments. I believe DigitalOcean, in particular, offers one of the easiest and most affordable deployment solutions. Take advantage of these services to launch your own projects with confidence!