Tethered local
Back to home
On this page
Note
This guide is an example for setting up a local development environment for Django. The recommended tool for local development is DDEV. See the Django DDEV guide.
To test changes locally, you can connect your locally running Django server to service containers on an active Platform.sh environment.
Before you begin
You need:
-
A local copy of the repository for a Django project running on Platform.sh.
To get one, run
platform get PROJECT_ID
.Alternatively, you can clone an integrated source repository and set the remote branch. To do so, run
platform project:set-remote PROJECT_ID
. -
The Platform.sh CLI
Assumptions
This example makes some assumptions, which you may need to adjust for your own circumstances.
It’s assumed you want to run a built-in lightweight development server with manage.py runserver
.
To match a production web server (such as Gunicorn or Daphne),
modify those commands accordingly.
It’s generally assumed that Platform.sh is the primary remote for the project. If you use a source integration, the steps are identical in most cases. When they differ, the alternative is noted.
If you followed the Django deployment guide, you should have a Django configuration file with settings for decoding variables and also overrides for Platform.sh.
You can use these settings to set up a tethered connection to services running on a Platform.sh environment. The settings are used to mock the conditions of the environment locally.
Create the tethered connection
-
Create a new environment based on production.
platform branch new-feature PRODUCTION_ENVIRONMENT_NAME
If you’re using a source integration, open a merge/pull request.
-
To open an SSH tunnel to the new environment’s services, run the following command:
platform tunnel:open
This command returns the addresses for SSH tunnels to all of your services.
-
Export the
PLATFORMSH_RELATIONSHIPS
environment variable with information from the open tunnel:export PLATFORM_RELATIONSHIPS="$(platform tunnel:info --encode)"
-
To ensure your
settings.py
file acts as if in a Platform.sh environment, mock two variables present in active environments:export PLATFORM_APPLICATION_NAME=django && export PLATFORM_ENVIRONMENT=new-feature
-
To install dependencies, run the command for your package manager:
-
Collect static assets.
-
To start your local server, run the following command based on your package manager:
-
When you’ve finished your work, close the tunnels to your services by running the following command:
platform tunnel:close --all -y
Next steps
You can now use your local environment to develop changes for review on Platform.sh environments. The following examples show how you can take advantage of that.
Onboard collaborators
It’s essential for every developer on your team to have a local development environment to work on. Place the local configuration into a script to ensure everyone has this. You can merge this change into production.
-
Create a new environment called
local-config
. -
To set up a local environment for a new Platform.sh environment, create an executable script.
touch init-local.sh && chmod +x init-local.sh
-
Fill it with the following example, depending on your package manager:
init-local.sh#!/usr/bin/env bash PROJECT=$1 ENVIRONMENT=$2 PARENT=$3 # Create the new environment platform branch $ENVIRONMENT $PARENT # Configure DDEV ddev config --auto ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT ddev config --webimage-extra-packages python-is-python3 ddev get drud/ddev-platformsh # Update .ddev/config.platformsh.yaml # 1. hooks.post-start printf " # Platform.sh start command\n - exec: |\n python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml # 2. php_version grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml # Create a docker-compose.django.yaml printf " version: \"3.6\" services: web: expose: - 8000 environment: - HTTP_EXPOSE=80:8000 - HTTPS_EXPOSE=443:8000 healthcheck: test: \"true\" " > .ddev/docker-compose.django.yaml # Create Dockerfile.python printf " RUN apt-get install -y python3.10 python3-pip " > .ddev/web-build/Dockerfile.python ddev start ddev pull platform -y ddev restart
init-local.sh#!/usr/bin/env bash PROJECT=$1 ENVIRONMENT=$2 PARENT=$3 # Create the new environment platform branch $ENVIRONMENT $PARENT # Configure DDEV ddev config --auto ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT ddev config --webimage-extra-packages python-is-python3 ddev get drud/ddev-platformsh # Update .ddev/config.platformsh.yaml # 1. hooks.post-start printf " # Platform.sh start command\n - exec: |\n pipenv run python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml # 2. php_version grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml # Create a docker-compose.django.yaml printf " version: \"3.6\" services: web: expose: - 8000 environment: - HTTP_EXPOSE=80:8000 - HTTPS_EXPOSE=443:8000 healthcheck: test: \"true\" " > .ddev/docker-compose.django.yaml # Create Dockerfile.python printf " RUN apt-get install -y python3.10 python3-pip " > .ddev/web-build/Dockerfile.python ddev start ddev pull platform -y ddev restart
init-local.sh#!/usr/bin/env bash PROJECT=$1 ENVIRONMENT=$2 PARENT=$3 # Create the new environment platform branch $ENVIRONMENT $PARENT # Configure DDEV ddev config --auto ddev config --web-environment-add PLATFORM_PROJECT=$PROJECT ddev config --web-environment-add PLATFORM_ENVIRONMENT=$ENVIRONMENT ddev config --webimage-extra-packages python-is-python3 ddev get drud/ddev-platformsh # Update .ddev/config.platformsh.yaml # 1. hooks.post-start printf " # Platform.sh start command\n - exec: |\n poetry run python manage.py runserver 0.0.0.0:8000" >> .ddev/config.platformsh.yaml # 2. php_version grep -v "php_version" .ddev/config.platformsh.yaml > tmpfile && mv tmpfile .ddev/config.platformsh.yaml printf "\nphp_version: 8.0" >> .ddev/config.platformsh.yaml # Create a docker-compose.django.yaml printf " version: \"3.6\" services: web: expose: - 8000 environment: - HTTP_EXPOSE=80:8000 - HTTPS_EXPOSE=443:8000 healthcheck: test: \"true\" " > .ddev/docker-compose.django.yaml # Create Dockerfile.python printf " RUN apt-get install -y python3.10 python3-pip " > .ddev/web-build/Dockerfile.python ddev start ddev pull platform -y ddev restart
-
To commit and push the revisions, run the following command:
git add . && git commit -m "Add local configuration" && git push platform local-config
-
Merge the change into production.
Once the script is merged into production, any user can set up their local environment by running the following commands:
platform PROJECT_ID
cd PROJECT_NAME
./init-local.sh PROJECT_ID another-new-feature PRODUCTION_ENVIRONMENT_NAME
Sanitize data
It’s often a compliance requirement to ensure that only a minimal subset of developers within an organization have access to production data during their work. By default, your production data is automatically cloned into every child environment.
You can customize your deployments to include a script that sanitizes the data within every preview environment.
-
Create a new environment called
sanitize-non-prod
. -
Follow the example on how to sanitize PostgreSQL with Django. This adds a sanitization script to your deploy hook that runs on all preview environments.
-
Commit and push the revisions by running the following command:
git add . && git commit -m "Add data sanitization" && git push platform sanitize-non-prod
-
Merge the change into production.
Once the script is merged into production, every preview environment created on Platform.sh and all local environments contain sanitized data free of your users’ personally identifiable information (PII).