Deploying an app is tremendously satisfying when it works, especially if you’ve never done it before. However, there are many obstacles that can arise in the deployment process, and unfortunately, some of these issues can be difficult to identify and address. This appendix will help you understand modern approaches to deployment and give you specific ways to troubleshoot the deployment process when things aren’t working.
If the additional information in this appendix isn’t enough to help you get through the deployment process successfully, see the online resources at https://ehmatthes.github.io/pcc_3e; the updates there will almost certainly help you carry out a successful deployment.
When you’re trying to troubleshoot a particular deployment attempt, it’s helpful to have a clear understanding of how a typical deployment works. Deployment refers to the process of taking a project that works on your local system, and copying that project to a remote server in a way that allows it to respond to requests from any user on the internet. The remote environment differs from a typical local system in a number of important ways: it’s probably not the same operating system (OS) as the one you’re using, and it’s most likely one of many virtual servers on a single physical server.
When you deploy a project, or push it to the remote server, the following steps need to be taken:
When you consider all that goes into a deployment, it’s no wonder deployments often fail. Fortunately, once you gain an understanding of what should be happening, you’ll stand a better chance of identifying what went wrong. If you can identify what went wrong, you might be able to identify a fix that will make the next deployment attempt successful.
You can develop locally on one kind of OS and push to a server running a different OS. It’s important to know what kind of system you’re pushing to, because that can inform some of your troubleshooting work. At the time of this writing, a basic remote server on Platform.sh runs Debian Linux; most remote servers are Linux-based systems.
Some troubleshooting steps are specific to each OS, but we’ll get to that in a moment. First, let’s consider the steps everyone should try when troubleshooting a deployment.
Your best resource is the output generated during the attempted push. This output can look intimidating; if you’re new to deploying apps, it can look highly technical, and there’s usually a lot of it. The good news is you don’t need to understand everything in the output. You should have two goals when skimming log output: identify any deployment steps that worked, and identify any steps that didn’t. If you can do this, you might be able to figure out what to change in your project, or in your deployment process, to make your next push successful.
Sometimes, the platform you’re pushing to will generate a message that has a clear suggestion for how to address the issue. For example, here’s the message you’ll see if you create a Platform.sh project before initializing a Git repository, and then try to push the project:
$ platform push
❶ Enter a number to choose a project:
[0] ll_project (votohz445ljyg)
> 0
❷ [RootNotFoundException]
Project root not found. This can only be run from inside a project directory.
❸ To set the project for this Git repository, run:
platform project:set-remote [id]
We’re trying to push a project, but the local project hasn’t been associated with a remote project yet. So, the Platform.sh CLI asks which remote project we want to push to ❶. We enter 0, to select the only project listed. But next, we see a RootNotFoundException ❷. This happens because Platform.sh looks for a .git directory when it inspects the local project, to figure out how to connect the local project with the remote project. In this case, since there was no .git directory when the remote project was created, that connection was never established. The CLI suggests a fix ❸; it’s telling us that we can specify the remote project that should be associated with this local project, using the project:set-remote command.
Let’s try this suggestion:
$ platform project:set-remote votohz445ljyg
Setting the remote project for this repository to: ll_project (votohz445ljyg)
The remote project for this repository is
now set to: ll_project (votohz445ljyg)
In the previous output, the CLI showed the ID of this remote project, votohz4451jyg. So we run the command that’s suggested, using this ID, and the CLI is able to make the connection between the local project and the remote project.
Now let’s try to push the project again:
$ platform push
Are you sure you want to push to the main (production) branch? [Y/n] y
Pushing HEAD to the existing environment main
--snip--
This was a successful push; following the onscreen suggestion worked.
You should be careful about running commands that you don’t fully understand. However, if you have good reason to believe that a command can do little harm, and if you trust the source of the recommendation, it might be reasonable to try the suggestions offered by the tools you’re using.
As mentioned earlier, the log output that you see when you run a command like platform push can be both informative and intimidating. Read through the following snippet of log output, taken from a different attempt at using platform push, and see if you can spot the issue:
--snip--
Collecting soupsieve==2.3.2.post1
Using cached soupsieve-2.3.2.post1-py3-none-any.whl (37 kB)
Collecting sqlparse==0.4.2
Using cached sqlparse-0.4.2-py3-none-any.whl (42 kB)
Installing collected packages: platformshconfig, sqlparse,...
Successfully installed Django-4.1 asgiref-3.5.2 beautifulsoup4-4.11.1...
W: ERROR: Could not find a version that satisfies the requirement gunicorrn
W: ERROR: No matching distribution found for gunicorrn
130 static files copied to '/app/static'.
Executing pre-flight checks...
--snip--
When a deployment attempt fails, a good strategy is to look through the log output and see if you can spot anything that looks like warnings or errors. Warnings are fairly common; they’re often messages about upcoming changes in a project’s dependencies, to help developers address issues before they cause actual failures.
A successful push may have warnings, but it shouldn’t have any errors. In this case, Platform.sh couldn’t find a way to install the requirement gunicorrn. This is a typo in the requirements_remote.txt file, which was supposed to include gunicorn (with one r). It’s not always easy to spot the root issue in log output, especially when the problem causes a bunch of cascading errors and warnings. Just like when reading a traceback on your local system, it’s a good idea to look closely at the first few errors that are listed, and also the last few errors. Most of the errors in between tend to be internal packages complaining that something went wrong, and passing messages about the error to other internal packages. The actual error we can fix is usually one of the first or last errors listed.
Sometimes, you’ll be able to spot the error, and other times, you’ll have no idea what the output means. It’s certainly worth a try, and using log output to successfully diagnose an error is a tremendously satisfying feeling. As you spend more time looking through log output, you’ll get better at identifying the information that’s most meaningful to you.
You can develop on any operating system you like and push to any host you like. The tools for pushing projects have developed enough that they’ll modify your project as needed to run correctly on the remote system. However, there are some OS-specific issues that can arise.
In the Platform.sh deployment process, one of the most likely sources of difficulties is installing the CLI. Here’s the command to do so:
$ curl -fsS https://platform.sh/cli/installer | php
The command starts with curl, a tool that lets you request remote resources, accessed through a URL, within a terminal. Here, it’s being used to download the CLI installer from a Platform.sh server. The -fsS section of the command is a set of flags that modify how curl runs. The f flag tells curl to suppress most error messages, so the CLI installer can handle them instead of reporting them all to you. The s flag tells curl to run silently; it lets the CLI installer decide what information to show in the terminal. The S flag tells curl to show an error message if the overall command fails. The | php at the end of the command tells your system to run the downloaded installer file using a PHP interpreter, because the Platform.sh CLI is written in PHP.
This means your system needs curl and PHP in order to install the Platform.sh CLI. To use the CLI, you’ll also need Git, and a terminal that can run Bash commands. Bash is a language that’s available in most server environments. Most modern systems have plenty of room for multiple tools like this to be installed.
The following sections will help you address these requirements for your OS. If you don’t already have Git installed, see the instructions for installing Git on page 484 in Appendix D and then go to the section here that’s applicable to your OS.
Windows has seen a resurgence in popularity with programmers in recent years. Windows has integrated many different elements of other operating systems, providing users with a number of options for how to do local development work and interact with remote systems.
One of the most significant difficulties in deploying from Windows is that the core Windows operating system is not the same as what a Linux-based remote server uses. A base Windows system has a different set of tools and languages than a base Linux system, so to carry out deployment work from Windows, you’ll need to choose how to integrate Linux-based tool sets into your local environment.
One popular approach is to use Windows Subsystem for Linux (WSL), an environment that allows Linux to run directly on Windows. If you have WSL set up, using the Platform.sh CLI on Windows becomes as easy as using it on Linux. The CLI won’t know it’s running on Windows; it will just see the Linux environment you’re using it in.
Setting up WSL is a two-step process: you first install WSL, and then choose a Linux distribution to install into the WSL environment. Setting up a WSL environment is more than can be described here; if you’re interested in this approach and don’t already have it set up, see the documentation at https://docs.microsoft.com/en-us/windows/wsl/about. Once you have WSL set up, you can follow the instructions in the Linux section of this appendix to continue your deployment work.
Another approach to building a local environment that you can deploy from uses Git Bash, a terminal environment that’s compatible with Bash but runs on Windows. Git Bash is installed along with Git when you use the installer from https://git-scm.com. This approach can work, but it isn’t as streamlined as WSL. In this approach, you’ll have to use a Windows terminal for some steps and a Git Bash terminal for others.
First you’ll need to install PHP. You can do this with XAMPP, a package that bundles PHP with a few other developer-focused tools. Go to https://apachefriends.org and click the button to download XAMPP for Windows. Open the installer and run it; if you see a warning about User Account Control (UAC) restrictions, click OK. Accept all of the installer’s defaults.
When the installer finishes running, you’ll need to add PHP to your system’s path; this will tell Windows where to look when you want to run PHP. In the Start menu, enter path and click Edit the System Environment Variables; click the button labeled Environment Variables. You should see the variable Path highlighted; click Edit under this pane. Click New to add a new path to the current list of paths. Assuming you kept the default settings when running the XAMPP installer, add C:\xampp\php in the box that appears, then click OK. When you’re finished, close all of the system dialogs that are still open.
With these requirements taken care of, you can install the Platform.sh CLI. You’ll need to use a Windows terminal with administrator privileges; enter command into the Start menu, and under the Command Prompt app, click Run as administrator. In the terminal that appears, enter the following command:
> curl -fsS https://platform.sh/cli/installer | php
This will install the Platform.sh CLI, as described earlier.
Finally, you’ll work in Git Bash. To open a Git Bash terminal, go to the Start menu and search for git bash. Click the Git Bash app that appears; you should see a terminal window open. You can use traditional Linux-based commands like ls in this terminal, as well as Windows-based commands like dir. To make sure the installation was successful, issue the platform list command. You should see a list of all the commands in the Platform.sh CLI. From this point forward, carry out all of your deployment work using the Platform.sh CLI inside a Git Bash terminal window.
The macOS operating system is not based on Linux, but they were both developed on similar principles. What this means, practically, is that a lot of the commands and workflows that you use on macOS will work in a remote server environment as well. You might need to install some developer-focused resources in order to have all of these tools available in your local macOS environment. If you get a prompt to install the command line developer tools at any point in your work, click Install to approve the installation.
The most likely difficulty when installing the Platform.sh CLI is making sure PHP is installed. If you see a message that the php command is not found, you’ll need to install PHP. One of the easiest ways to install PHP is by using the Homebrew package manager, which facilitates the installation of a wide variety of packages that programmers depend on. If you don’t already have Homebrew installed, visit https://brew.sh and follow the instructions to install it.
Once Homebrew is installed, use the following command to install PHP:
$ brew install php
This will take a while to run, but once it has completed, you should be able to successfully install the Platform.sh CLI.
Because most server environments are Linux-based, you should have very little difficulty installing and using the Platform.sh CLI. If you try to install the CLI on a system with a fresh installation of Ubuntu, it will tell you exactly which packages you need:
$ curl -fsS https://platform.sh/cli/installer | php
Command 'curl' not found, but can be installed with:
sudo apt install curl
Command 'php' not found, but can be installed with:
sudo apt install php-cli
The actual output will have more information about a few other packages that would work, plus some version information. The following command will install curl and PHP:
$ sudo apt install curl php-cli
After running this command, the Platform.sh CLI installation command should run successfully. Since your local environment is quite similar to most Linux-based hosting environments, much of what you learn about working in your terminal will carry over to working in a remote environment as well.
If Platform.sh doesn’t work for you, or if you want to try a different approach, there are many hosting platforms to choose from. Some work similarly to the process described in Chapter 20, and some have a much different approach to carrying out the steps described at the beginning of this appendix:
New hosting platforms and approaches appear on a regular basis; find one that looks appealing to you, and invest the time to learn that provider’s deployment process. Maintain your project long enough so that you get to know what works well with your provider’s approach and what doesn’t. No hosting platform is going to be perfect; you’ll need to make an ongoing judgement call about whether the provider you’re currently using is good enough for your use case.
I’ll offer one last word of caution about choosing a deployment platform and an overall approach to deployment. Some people will enthusiastically steer you toward overly complex deployment approaches and services that are meant to make your project highly reliable and capable of serving millions of users simultaneously. Many programmers spend lots of time, money, and energy building out a complex deployment strategy, only to find that hardly anyone is using their project. Most Django projects can be set up on a small hosting plan and tuned to serve thousands of requests per minute. If your project is getting anything less than this level of traffic, take the time to configure your deployment to work well on a minimal platform before investing in infrastructure that’s meant for some of the largest sites in the world.
Deployment is incredibly challenging at times, but just as satisfying when your live project works well. Enjoy the challenge, and ask for help when you need it.