Poetry is an open-source tool for managing and packaging dependencies for Python projects. It maintains a clean view of your dependency tree, streamlines the installation and management of dependencies, and simplifies packaging and distribution to PyPI. This guide installs Poetry with Pipx on Ubuntu 24.04, creates a virtual environment, and runs a Flask application using Poetry and Gunicorn. By the end, you'll have a Flask app managed entirely through Poetry, tested with Pytest, and served in production mode with Gunicorn.
Prerequisites
Before you begin, you need to:
- Have access to an Ubuntu 24.04 server.
Install Poetry with Pipx
Installing Poetry in an isolated environment prevents conflicts between Poetry's internal dependencies and system-wide dependencies.
1. Update the APT package index:
$ sudo apt update
2. Install Pipx:
$ sudo apt install pipx -y
3. Add the Pipx libraries to your system's PATH:
$ pipx ensurepath
4. Enable tab completions for Pipx commands:
$ echo 'eval "$(register-python-argcomplete pipx)"' >> ~/.bashrc
5. Reload the .bashrc shell configuration to apply the changes in your active session:
$ source ~/.bashrc
6. Install Poetry using Pipx:
$ pipx install poetry
Your output should be similar to the one below:
installed package poetry 2.0.0, installed using Python 3.12.3
These apps are now globally available
- poetry
done! ✨ 🌟 ✨
7. View the installed Poetry version:
$ poetry --version
Your output should be similar to the one below:
Poetry (version 2.0.0)
Create a Poetry Project
1. Create a new flask-app Poetry project:
$ poetry new flask-app
This creates a flask-app directory with the following files:
-
flask_app: Contains an__init__.pyfile that specifies all Flask code, including modules, functions, and other related support components. -
pyproject.toml: Includes information about the project, Poetry configuration, and installed dependencies. -
README.md: Includes basic documentation about the project. -
tests: Integrates and organizes the project's test cases.
Your output should be similar to the one below:
Created package flask_app in flask-app
2. Switch to the flask-app project directory:
$ cd flask-app
Create a Virtual Environment and Install Flask
1. Specify the Python interpreter for Poetry and create a new virtual environment:
$ poetry env use python3
This instructs Poetry to use the default Python3 interpreter on your system. You can also target a specific version, such as poetry env use python3.11, if that version is installed.
Your output should be similar to the one below:
Creating virtualenv flask-app-vnQ3DaWl-py3.12 in /home/linuxuser/.cache/pypoetry/virtualenvs
Using virtualenv: /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12
2. Activate the virtual environment:
$ poetry env activate
This outputs the command to run in order to activate the virtual environment manually. Your output should be similar to the one below:
source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
3. Activate the virtual environment using its path:
$ source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
Your output should be similar to the one below when the virtual environment is activated:
(flask-app-py3.12) linuxuser@:~/flask-app$
4. Install Flask using Poetry:
$ poetry add flask
This installs Flask with all dependencies in the active virtual environment, adds the installed Flask version to pyproject.toml, and creates a poetry.lock file for deterministic builds.
Your output should be similar to the one below:
Using version ^3.1.0 for flask
Updating dependencies
Resolving dependencies... (0.2s)
Package operations: 7 installs, 0 updates, 0 removals
- Installing markupsafe (3.0.2)
- Installing blinker (1.9.0)
- Installing click (8.1.8)
- Installing itsdangerous (2.2.0)
- Installing jinja2 (3.1.5)
- Installing werkzeug (3.1.3)
- Installing flask (3.1.0)
Writing lock file
5. Deactivate the virtual environment:
$ deactivate
Set Up Firewall Rules
Uncomplicated Firewall (UFW) is active on most Ubuntu 24.04 servers by default. Configure UFW to allow connections to the Flask application port 5000.
1. Allow connections to the Flask application port 5000:
$ sudo ufw allow 5000/tcp
2. Reload UFW to apply the firewall configuration changes:
$ sudo ufw reload
3. View the UFW status and verify that the rule is active:
$ sudo ufw status
Your output should be similar to the one below:
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
5000/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
5000/tcp (v6) ALLOW Anywhere (v6)
Run the Flask App with Poetry
1. Retrieve the command to reactivate the virtual environment:
$ poetry env activate
Your output should be similar to the one below:
source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
2. Activate the virtual environment:
$ source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
3. Navigate to the flask_app directory:
$ cd flask_app
4. Create a file app.py using nano:
$ nano app.py
5. Add the following code:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "<h1>Hello from Flask</h1>"
if __name__ == '__main__':
app.run(host='0.0.0.0', port='5000')
Save the file with Ctrl+X, then Y, then Enter. This creates a webpage that returns Hello from Flask on the home route /.
6. Run the Flask application:
$ poetry run python app.py
Your output should be similar to the one below:
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://<SERVER-IP>:5000
Press CTRL+C to quit
7. Access your Flask app using the following address in a web browser. Replace <SERVER-IP> with your server's IP address:
http://<SERVER-IP>:5000
8. To stop the Flask app, press Ctrl+C in your terminal session.
Create Group Dependencies
Poetry allows you to manage dependencies using groups. Follow these steps to create a group called dev and install Pytest for testing.
1. Install Pytest in the dev dependency group:
$ poetry add pytest --group dev
This creates a new section in pyproject.toml — [tool.poetry.group.dev.dependencies] — which includes dependencies such as pytest = "^8.3.4" under the dev group. Production dependencies should not be added to any group; they belong under the root dependencies ([tool.poetry.dependencies]) instead, so they aren't excluded during deployment or packaging.
2. Navigate to your project's tests directory:
$ cd ~/flask-app/tests
3. Create a new directory named unit:
$ mkdir unit
4. Navigate into the unit directory:
$ cd unit
5. Create an __init__.py file:
$ touch __init__.py
This marks the directory as a Python package, allowing you to import modules from it.
6. Create a test file test_app.py using nano:
$ nano test_app.py
7. Add the following code to the file:
import pytest
from flask_app.app import app
@pytest.fixture
def client():
with app.test_client() as client:
yield client
def test_the_home_route(client):
response = client.get('/')
assert response.status_code == 200
assert b"<h1>Hello from Flask</h1>" in response.data
Save the file with Ctrl+X, then Y, then Enter. This checks that the response body from app.py contains the markup <h1>Hello from Flask</h1>.
8. Run the test:
$ pytest
Your output should be similar to the one below:
platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.5.0
rootdir: /home/linuxuser/flask-app
configfile: pyproject.toml
collected 1 item
test_app.py . [100%]
============================= 1 passed in 0.11s ==============================
Install Gunicorn, a WSGI HTTP Server, with Flask
A WSGI HTTP server such as Gunicorn handles client requests concurrently and efficiently, making it ideal for production-grade Flask applications.
1. Navigate to the flask_app directory:
$ cd ~/flask-app/flask_app
2. Add Gunicorn as a root dependency:
$ poetry add gunicorn
3. Create a wsgi.py file using nano:
$ nano wsgi.py
4. Add the following Python code:
from app import app
if __name__ == '__main__':
app.run()
5. Run the Flask app with Gunicorn:
$ gunicorn --bind 0.0.0.0:5000 wsgi:app
6. Check that your Flask app is still accessible:
http://<SERVER-IP>:5000
7. Press Ctrl+C to stop the server.
Manage the Virtual Environment
1. Exit the virtual environment:
$ deactivate
2. List all virtual environments for your project:
$ poetry env list
The environment labeled (Activated) is the one in use. Your output should be similar to the one below:
flask-app-vnQ3DaWl-py3.12 (Activated)
3. Copy the environment name from the previous command's output and remove the virtual environment:
$ poetry env remove flask-app-vnQ3DaWl-py3.12
Your output should be similar to the one below:
Deleted virtualenv: /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12
4. Recreate the virtual environment:
$ poetry env use python3
5. Retrieve the command to reactivate the virtual environment:
$ poetry env activate
Your output should be similar to the one below:
source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
6. Activate the virtual environment by copying and running the activation command from the previous step:
$ source /home/linuxuser/.cache/pypoetry/virtualenvs/flask-app-vnQ3DaWl-py3.12/bin/activate
7. Install all the dependencies from the pyproject.toml file:
$ poetry install
With the pyproject.toml file present, the virtual environment and dependencies can always be recreated and reinstalled.
Modify the Virtual Environment Location
By default, Poetry creates a virtual environment in /.cache/pypoetry/virtualenvs. To keep the virtual environment organized alongside your project files, you can move its location to the root of your project.
1. Exit the virtual environment:
$ deactivate
2. List the virtual environments for your project:
$ poetry env list
Your output should be similar to the one below:
flask-app-vnQ3DaWl-py3.12 (Activated)
3. Remove the virtual environment:
$ poetry env remove flask-app-vnQ3DaWl-py3.12
4. Configure Poetry to allow the virtual environment to be created at the root of your project:
$ poetry config virtualenvs.in-project true
This overwrites the default configuration set by Poetry and allows the virtual environment to be created in the root of your project.
5. Verify that the configuration change is applied:
$ poetry config virtualenvs.in-project
Your output should be similar to the one below:
true
6. Create a virtual environment to verify:
$ poetry env use python3
Your output should be similar to the one below:
Creating virtualenv flask-app in /home/linuxuser/flask-app/.venv
Using virtualenv: /home/linuxuser/flask-app/.venv
7. Retrieve the command to activate the virtual environment:
$ poetry env activate
Your output should be similar to the one below:
source /home/linuxuser/flask-app/.venv/bin/activate
8. Activate the virtual environment:
$ source /home/linuxuser/flask-app/.venv/bin/activate
9. View your virtual environment information:
$ poetry env info
Your output should be similar to the one below:
Virtualenv
Python: 3.12.3
Implementation: CPython
Path: /home/linuxuser/flask-app/.venv
Executable: /home/linuxuser/flask-app/.venv/bin/python
Valid: True
Base
Platform: linux
OS: posix
Python: 3.12.3
Path: /usr
Executable: /usr/bin/python3.12
10. Install all the dependencies in this new environment:
$ poetry install
11. Run the Flask app using Gunicorn to verify that everything is running in the new environment:
$ gunicorn --bind 0.0.0.0:5000 wsgi:app
12. Check that your Flask app is accessible:
http://<SERVER-IP>:5000
Next Steps
- Put Gunicorn behind a reverse proxy such as Nginx and run it as a systemd service for production deployments.
- Add more Poetry dependency groups (for example,
lintordocs) to keep tooling separate from runtime dependencies. - Wire the Pytest suite into a CI pipeline so tests run automatically on every push.
- Publish the package to PyPI or a private repository once it's ready to share.
For the full guide with additional tips, visit the original article on Vultr Docs.

Top comments (0)