Production Deployment
Throughout this course, we have developed and tested the Student Management System on our local machine. Although the application works correctly, it is currently accessible only from our computer. To make the application available to users over the internet, we need to deploy it to a production server. This process is known as application deployment. In this chapter, we will prepare our application for Docker, configure database migrations using Alembic, run the application using Docker Compose, and finally deploy it to a DigitalOcean Virtual Private Server (VPS). We will also configure Nginx as a reverse proxy and secure the application using HTTPS. By the end of this chapter, your application will be running on a production server and accessible securely using your own domain name.Learning Outcomes
By the end of this chapter, you will be able to:- Prepare a FastAPI application for Docker.
- Configure database migrations using Alembic.
- Configure multiple containers using Docker Compose.
- Build and test the application locally.
- Deploy the application to DigitalOcean.
- Configure Nginx as a reverse proxy.
- Secure the application using HTTPS.
Technologies Used
Deployment Workflow
During this chapter, we will complete the following steps.- Prepare the application for Docker.
- Prepare database migrations.
- Configure Docker Compose.
- Build and test the application.
- Publish the project to GitHub.
- Deploy the application to DigitalOcean.
- Configure Nginx.
- Enable HTTPS.
- Verify the deployment.
Step 1 - Preparing the Application for Docker
Before deploying our application, we need to prepare it for Docker. In this step, we will create the Docker configuration files required to build our application image. We are not going to build or run the application yet. By the end of this step, you will:- Understand the purpose of Docker.
- Create a
.dockerignorefile. - Create a
Dockerfile. - Understand how Docker builds an application image.
Note TheCreating the.envanddocker-compose.ymlfiles will be created in a later step. They are shown here to give you an overview of the final project structure.
.dockerignore File
Docker copies the project into a temporary build context before creating the image.
Some files should not be copied because they increase the image size or are only useful during development.
Create a file named .dockerignore.
- Which base operating system image to use.
- Which software packages to install.
- Which project files to copy.
- Which command to execute when the container starts.
Summary
In this step, we prepared our application for Docker by creating the required configuration files.
The application has not been built or executed yet.
Step 2 - Preparing Database Migrations
Our application uses Alembic to manage database schema changes. Before running the application inside Docker, we need to prepare Alembic so it can automatically create or update the database whenever the application starts. In this step, we will configure Alembic and generate the initial migration script. We are not going to execute any migrations yet because the PostgreSQL database container has not been created. By the end of this step, you will:- Configure Alembic.
- Connect Alembic to the application.
- Generate the initial migration.
- Prepare Alembic for automatic execution.
alembic.ini
Open alembic.ini.
Replace
env.py
Open alembic/env.py.
Configure Alembic to use the application’s metadata and database URL.
Note We are not executing the migration in this step. In the next step, we will configure Docker Compose and PostgreSQL. Once the PostgreSQL container is available, Docker Compose will automatically execute:Summary In this step, we prepared Alembic by configuring the migration environment and generating the initial migration script. In the next step, we will configure Docker Compose, create the PostgreSQL container, and configure the FastAPI container to automatically execute pending migrations whenever it starts.before starting the FastAPI application.
Step 3 - Configuring Docker Compose
In the previous steps, we prepared our application for Docker and configured Alembic for database migrations. Now we will configure Docker Compose to manage both the FastAPI application and the PostgreSQL database. Docker Compose allows us to define multiple services in a single configuration file and start them together using one command. In this step, we will:- Create the
.envfile. - Configure the PostgreSQL container.
- Configure the FastAPI container.
- Configure persistent database storage.
- Automatically execute database migrations before starting the application.
.env File
Instead of hardcoding configuration values inside our application, we store them in a .env file.
Create a file named .env in the project root.
Note Notice that the hostname is db instead of localhost. Docker Compose automatically creates a private network where each service can communicate using its service name.Creating the Docker Compose File Create a file named docker-compose.yml in the project root.
services section defines all the containers required by our application.
In this project, we have two services.
Docker Compose automatically creates a private network so that the FastAPI container can communicate with the PostgreSQL container using the hostname db.
Understanding the PostgreSQL Service
The PostgreSQL service:
- Creates the database container.
- Creates the database specified in
.env. - Stores database files inside a persistent Docker volume.
- Verifies that PostgreSQL is ready using a health check.
- Builds the Docker image using the Dockerfile.
- Starts the FastAPI container.
- Reads the database connection string from
.env. - Waits until PostgreSQL becomes healthy.
command option.
- Connects to the PostgreSQL database.
- Executes any pending Alembic migrations.
- Starts the FastAPI application using Uvicorn.
Step 4 - Building and Testing the Application
In the previous steps, we prepared our application for Docker, configured Alembic, and created the Docker Compose configuration. Now everything is ready. In this step, we will build the Docker image, create the required containers, apply the pending database migrations, and start the FastAPI application. By the end of this step, you will be able to:- Build the Docker image.
- Start the application and database containers.
- Verify that database migrations are applied automatically.
- Test the FastAPI application.
- Verify database persistence.
- Builds the FastAPI Docker image.
- Creates the PostgreSQL container.
- Creates the FastAPI container.
- Waits until PostgreSQL is ready.
- Executes pending Alembic migrations.
- Starts the FastAPI application.
- Removing a container does not delete the database.
- Restarting the application does not lose data.
- Docker automatically reuses the existing volume when the containers are started again.
Summary
Congratulations! 🎉
You have successfully:
- Built the Docker image.
- Started the FastAPI and PostgreSQL containers.
- Applied database migrations automatically.
- Verified that the application is working.
- Confirmed that database data persists across container restarts.
Step 5 - Publishing the Latest Changes to GitHub
Throughout this course, we have been using Git to manage our project and committing our changes regularly. Before deploying the application, make sure your latest changes have been pushed to your GitHub repository. Checking the Repository Status Verify that there are no uncommitted changes.Note If all changes have already been committed and pushed, no further action is required.Summary The latest version of the application is now available in the GitHub repository. In the next step, we will clone the repository onto a DigitalOcean server and deploy the application.
Step 6 - Deploying the Application to DigitalOcean
Now that the latest version of our project is available on GitHub, we are ready to deploy it to a DigitalOcean Virtual Private Server (VPS). In this step, we will:- Create a DigitalOcean Droplet.
- Connect to the server using SSH.
- Install the required software.
- Clone the project from GitHub.
- Configure the production environment.
- Start the application using Docker Compose.
- Select the latest Ubuntu LTS image.
- Choose an appropriate plan.
- Add your SSH public key.
- Create the Droplet.
your_server_ip with the public IP address of your Droplet.
Installing Docker and Git
Update the package list.
.env file.
- Press Ctrl + O to write the file.
- Press Enter to confirm.
- Press Ctrl + X to exit the editor.
Tip
Replace your_secure_password with a strong password before deploying your application to production.
Tip Use a strong password for the production database instead of the password used during local development.Starting the Application Build the Docker image and start all containers.
- Builds the FastAPI image.
- Starts the PostgreSQL container.
- Waits until PostgreSQL is ready.
- Executes any pending Alembic migrations.
- Starts the FastAPI application.
- PostgreSQL started successfully.
- Alembic applied the database migrations.
- Uvicorn is running.
Step 7 - Configuring Nginx
At this stage, our FastAPI application is running on the DigitalOcean server and can be accessed using the server’s public IP address.- Users can access the application using a domain or subdomain.
- The application port remains hidden.
- HTTPS can be configured easily.
- Nginx efficiently handles incoming requests.
If you want to use the root domain, create the following record instead.
Replace your_server_ip with the public IP address of your DigitalOcean Droplet.
What is an A Record? An A (Address) Record maps a domain or subdomain directly to an IP address. For example:After creating the DNS record, wait a few minutes for the changes to propagate. You can verify the DNS configuration using either of the following commands.Since our application is deployed on a DigitalOcean Virtual Machine with a public IP address, an A Record is the appropriate DNS record to use.
Enabling the Configuration
Enable the new site.
Note At this stage, the application is accessible over HTTP only. In the next step, we will configure HTTPS using a free SSL certificate from Let’s Encrypt.Summary In this step, we:
- Configured a DNS A Record to point our domain or subdomain to the DigitalOcean server.
- Installed Nginx.
- Configured Nginx as a reverse proxy.
- Verified that the application is accessible using the configured domain or subdomain.
Step 8 - Enabling HTTPS
Our application is now accessible using a domain or subdomain.- Encrypts all communication between the client and server.
- Protects sensitive information during transmission.
- Increases user trust.
- Is required by many modern browsers and APIs.
- An email address for renewal notifications.
- Whether you agree to the Let’s Encrypt Terms of Service.
- Whether you want to share your email address with the Electronic Frontier Foundation (optional).
- The domain or subdomain you want to secure.
- Generates an SSL certificate.
- Updates the Nginx configuration.
- Enables HTTPS.
- Reloads Nginx.
- Installed Certbot.
- Generated a free SSL certificate using Let’s Encrypt.
- Configured Nginx to serve HTTPS.
- Verified automatic certificate renewal.
- Rebuilds the FastAPI Docker image.
- Starts the PostgreSQL container.
- Executes any pending Alembic migrations.
- Starts the FastAPI application.
Note
Since the PostgreSQL data is stored in a Docker volume, running docker compose down removes only the containers. The database data is preserved and will be reused when the containers are started again.