├── .gitignore ├── docker-compose.yml ├── flask ├── .dockerignore ├── Dockerfile ├── app.ini ├── app │ ├── __init__.py │ └── views.py ├── requirements.txt └── run.py ├── log ├── nginx │ └── readme.md └── uwsgi │ └── readme.md ├── nginx ├── Dockerfile └── nginx.conf └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | Skip to content 2 | 3 | Search or jump to… 4 | 5 | Pull requests 6 | Issues 7 | Marketplace 8 | Explore 9 | 10 | @Julian-Nash Sign out 11 | 0 12 | 0 0 Julian-Nash/simple-flask-demo 13 | Code Issues 0 Pull requests 0 Projects 0 Wiki Insights Settings 14 | simple-flask-demo/.gitignore 15 | @Julian-Nash Julian-Nash readme 16 | 9982754 6 days ago 17 | 123 lines (99 sloc) 1.56 KB 18 | 19 | # Byte-compiled / optimized / DLL files 20 | __pycache__/ 21 | *.py[cod] 22 | *$py.class 23 | 24 | # C extensions 25 | *.so 26 | 27 | # Distribution / packaging 28 | .Python 29 | build/ 30 | develop-eggs/ 31 | dist/ 32 | downloads/ 33 | eggs/ 34 | .eggs/ 35 | lib/ 36 | lib64/ 37 | parts/ 38 | sdist/ 39 | var/ 40 | wheels/ 41 | share/python-wheels/ 42 | *.egg-info/ 43 | .installed.cfg 44 | *.egg 45 | MANIFEST 46 | 47 | # PyInstaller 48 | # Usually these files are written by a python script from a template 49 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 50 | *.manifest 51 | *.spec 52 | 53 | # Installer logs 54 | pip-log.txt 55 | pip-delete-this-directory.txt 56 | 57 | # Unit test / coverage reports 58 | htmlcov/ 59 | .tox/ 60 | .nox/ 61 | .coverage 62 | .coverage.* 63 | .cache 64 | nosetests.xml 65 | coverage.xml 66 | *.cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | 70 | # Translations 71 | *.mo 72 | *.pot 73 | 74 | # Django stuff: 75 | *.log 76 | local_settings.py 77 | db.sqlite3 78 | 79 | # Flask stuff: 80 | instance/ 81 | .webassets-cache 82 | 83 | # Scrapy stuff: 84 | .scrapy 85 | 86 | # Sphinx documentation 87 | docs/_build/ 88 | 89 | # PyBuilder 90 | target/ 91 | 92 | # Jupyter Notebook 93 | .ipynb_checkpoints 94 | 95 | # IPython 96 | profile_default/ 97 | ipython_config.py 98 | 99 | # pyenv 100 | .python-version 101 | 102 | # celery beat schedule file 103 | celerybeat-schedule 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | .vscode 136 | dump.rdb 137 | guide.md 138 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | 5 | # Define our individual services 6 | 7 | flask: 8 | 9 | # Build the flask service using the Dockerfile in the flask directory 10 | build: ./flask 11 | 12 | # Give our flask container a friendly name 13 | container_name: flask 14 | 15 | # Instruct Docker to always restart the service 16 | restart: always 17 | 18 | # Use environment to set any environment variables 19 | environment: 20 | - APP_NAME=MyFlaskApp 21 | 22 | # Any ports listed using `expose` will only be accessible to internal services/containers 23 | # uWSGI will be serving our Flask application on port 8080 24 | expose: 25 | - 8080 26 | 27 | # Mount the container log directory to the local log directory 28 | # Consider changing this to /var/log/uwsgi:/var/log/uwsgi in production 29 | # Just make sure the directory exists before running docker-compose up --build 30 | volumes: 31 | - ./log/uwsgi:/var/log/uwsgi 32 | 33 | nginx: 34 | 35 | # Build the nginx service using the Dockerfile in the nginx directory 36 | build: ./nginx 37 | 38 | # Give our nginx container a friendly name 39 | container_name: nginx 40 | 41 | # Instruct Docker to always restart the service 42 | restart: always 43 | 44 | # Any ports listed using `ports` will be exposed to the outside world 45 | ports: 46 | - "80:80" 47 | 48 | # Mount the container log directory to the local log directory 49 | # Consider changing this to /var/log/nginx:/var/log/nginx in production 50 | # Just make sure the directory exists before running docker-compose up --build 51 | volumes: 52 | - ./log/nginx:/var/log/nginx 53 | 54 | -------------------------------------------------------------------------------- /flask/.dockerignore: -------------------------------------------------------------------------------- 1 | env/ 2 | __pycache__/ -------------------------------------------------------------------------------- /flask/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the Python3.7.2 container image 2 | FROM python:3.7.2-stretch 3 | 4 | # Set the working directory to /app 5 | WORKDIR /app 6 | 7 | # Copy the current directory contents into the container at /app 8 | ADD . /app 9 | 10 | # Install the dependencies 11 | RUN pip install -r requirements.txt 12 | 13 | # Create a uwsgi log directory and files 14 | RUN mkdir /var/log/uwsgi 15 | RUN touch /var/log/uwsgi/uwsgi_access.log 16 | RUN touch /var/log/uwsgi/uwsgi_error.log 17 | 18 | # run the command to start uWSGI 19 | CMD ["uwsgi", "app.ini"] -------------------------------------------------------------------------------- /flask/app.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | wsgi-file = run.py 3 | callable = app 4 | socket = :8080 5 | processes = 4 6 | threads = 2 7 | master = true 8 | chmod-socket = 660 9 | vacuum = true 10 | die-on-term = true 11 | logger = file:/var/log/uwsgi/uwsgi_error.log 12 | ; logformat = [%(ctime)] %(proto) %(status) %(method) %(uri) 13 | req-logger = file:/var/log/uwsgi/uwsgi_access.log -------------------------------------------------------------------------------- /flask/app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | from app import views -------------------------------------------------------------------------------- /flask/app/views.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | import os 4 | 5 | @app.route("/") 6 | def index(): 7 | 8 | # Use os.getenv("key") to get environment variables 9 | app_name = os.getenv("APP_NAME") 10 | 11 | if app_name: 12 | return f"Hello from {app_name} running in a Docker container behind Nginx!" 13 | 14 | return "Hello from Flask" -------------------------------------------------------------------------------- /flask/requirements.txt: -------------------------------------------------------------------------------- 1 | Click==7.0 2 | Flask==1.0.2 3 | itsdangerous==1.1.0 4 | Jinja2==2.10 5 | MarkupSafe==1.1.1 6 | uWSGI==2.0.18 7 | Werkzeug==0.15.1 8 | -------------------------------------------------------------------------------- /flask/run.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | if __name__ == "__main__": 4 | app.run() -------------------------------------------------------------------------------- /log/nginx/readme.md: -------------------------------------------------------------------------------- 1 | Directory for nginx logs 2 | 3 | A better choice in production may be to change the `volumes` section in the `docker-compose.yml` under the `nginx` service to the following: 4 | 5 | ```yml 6 | volumes: 7 | - ./var/log/nginx:/var/log/nginx 8 | ``` 9 | 10 | Just make sure this directory exists before running `docker-compose up --build` -------------------------------------------------------------------------------- /log/uwsgi/readme.md: -------------------------------------------------------------------------------- 1 | Directory for uWSGI logs 2 | 3 | A better choice in production may be to change the `volumes` section in the `docker-compose.yml` under the `flask` service to the following: 4 | 5 | ```yml 6 | volumes: 7 | - ./var/log/uwsgi:/var/log/uwsgi 8 | ``` 9 | 10 | Just make sure this directory exists before running `docker-compose up --build` -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the Nginx image 2 | FROM nginx 3 | 4 | # Remove the default nginx.conf 5 | RUN rm /etc/nginx/conf.d/default.conf 6 | 7 | # Replace with our own nginx.conf 8 | COPY nginx.conf /etc/nginx/conf.d/ -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | 5 | location / { 6 | include uwsgi_params; 7 | uwsgi_pass flask:8080; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### Simple Flask app running behind Nginx & uWSGI in a Docker container 2 | 3 | Clone the repo: 4 | 5 | ```sh 6 | git clone https://github.com/Julian-Nash/docker-flask-uwsgi-nginx-simple.git 7 | ``` 8 | 9 | To develop locally, create a new virtual env in the `flask` directory & run the app: 10 | 11 | ```sh 12 | cd app 13 | python -m venv env 14 | source env/bin/activate 15 | pip install -r requirements.txt 16 | export FLASK_APP=run.py 17 | export FLASK_ENV=development 18 | flask run 19 | ``` 20 | 21 | Go to - http://127.0.0.1:5000 22 | 23 | 24 | To run the container locally: 25 | 26 | ```sh 27 | docker-compose up --build 28 | ``` 29 | 30 | Go to - http://127.0.0.1/ 31 | 32 | ### Notes 33 | 34 | `nginx` logs and `uwsgi` logs will be logged to `log/nginx` and `log/uwsgi` respectively. This can be changed by changing the `volume` mounts in the `docker-compose.yml`. 35 | 36 | Alternatively, delete the `volumes` to have Docker log to `Stdout`. --------------------------------------------------------------------------------