From 07604014f2d4b91357adad6ccd446d3d78e4126e Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Thu, 18 Jul 2024 13:15:52 +0200 Subject: [PATCH] add reverse proxy and gunicorn to flask app (#5) * add proxy and gunicorn * update CI for changed folder structure --- .github/workflows/CI.yml | 2 +- Dockerfile | 10 +++++++ docker-compose.yml | 14 ++++++++++ requirements.txt | 1 + src/{ => app}/main.py | 0 src/{ => app}/tests/conftest.py | 0 src/{ => app}/tests/test_donate.py | 0 src/{ => app}/website/__init__.py | 2 +- src/{ => app}/website/about.py | 0 src/{ => app}/website/donate.py | 0 src/{ => app}/website/models.py | 0 src/{ => app}/website/templates/about.html | 0 src/{ => app}/website/templates/base.html | 0 src/{ => app}/website/templates/donate.html | 0 src/{ => app}/website/templates/home.html | 0 src/{ => app}/website/views.py | 0 src/app/wsgi.py | 7 +++++ src/gunicorn/gunicorn.conf.py | 8 ++++++ src/gunicorn/gunicorn.sh | 1 + src/nginx/conf/nginx.conf | 31 +++++++++++++++++++++ src/nginx/keys/localhost.crt | 19 +++++++++++++ src/nginx/keys/localhost.key | 28 +++++++++++++++++++ 22 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml rename src/{ => app}/main.py (100%) rename src/{ => app}/tests/conftest.py (100%) rename src/{ => app}/tests/test_donate.py (100%) rename src/{ => app}/website/__init__.py (95%) rename src/{ => app}/website/about.py (100%) rename src/{ => app}/website/donate.py (100%) rename src/{ => app}/website/models.py (100%) rename src/{ => app}/website/templates/about.html (100%) rename src/{ => app}/website/templates/base.html (100%) rename src/{ => app}/website/templates/donate.html (100%) rename src/{ => app}/website/templates/home.html (100%) rename src/{ => app}/website/views.py (100%) create mode 100644 src/app/wsgi.py create mode 100644 src/gunicorn/gunicorn.conf.py create mode 100644 src/gunicorn/gunicorn.sh create mode 100644 src/nginx/conf/nginx.conf create mode 100644 src/nginx/keys/localhost.crt create mode 100644 src/nginx/keys/localhost.key diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2557c2c..64918a8 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -31,7 +31,7 @@ jobs: env: FLASK_SECRET_KEY: ${{ secrets.FLASK_SECRET_KEY }} run: | - cd src + cd src/app python -m pytest -svv --cov=. --cov-report=xml - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..14486ef --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python +WORKDIR /app + +COPY ./src/app /app +COPY ./requirements.txt /app + +RUN pip install --upgrade pip +RUN pip install -r requirements.txt + +ENV FLASK_SECRET_KEY "sdfk" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..34e1c54 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + nginx: + image: nginx + ports: + - "8080:80" + - "8443:443" + volumes: + - ./src/nginx/conf/:/etc/nginx/conf.d/:ro + - ./src/nginx/keys/:/etc/nginx/ssl/:ro + webapp: + build: . + command: gunicorn --bind 0.0.0.0:8000 wsgi:app + expose: + - "8000" diff --git a/requirements.txt b/requirements.txt index 4594725..eaa1397 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ flask flask-sqlalchemy sqlalchemy +gunicorn pytest pytest-cov \ No newline at end of file diff --git a/src/main.py b/src/app/main.py similarity index 100% rename from src/main.py rename to src/app/main.py diff --git a/src/tests/conftest.py b/src/app/tests/conftest.py similarity index 100% rename from src/tests/conftest.py rename to src/app/tests/conftest.py diff --git a/src/tests/test_donate.py b/src/app/tests/test_donate.py similarity index 100% rename from src/tests/test_donate.py rename to src/app/tests/test_donate.py diff --git a/src/website/__init__.py b/src/app/website/__init__.py similarity index 95% rename from src/website/__init__.py rename to src/app/website/__init__.py index db37539..0ce11af 100644 --- a/src/website/__init__.py +++ b/src/app/website/__init__.py @@ -28,7 +28,7 @@ def create_app(): app.register_blueprint(donate, url_prefix="/") app.register_blueprint(about, url_prefix="/") - from .models import RawData + from .models import RawData # noqa with app.app_context(): db.create_all() diff --git a/src/website/about.py b/src/app/website/about.py similarity index 100% rename from src/website/about.py rename to src/app/website/about.py diff --git a/src/website/donate.py b/src/app/website/donate.py similarity index 100% rename from src/website/donate.py rename to src/app/website/donate.py diff --git a/src/website/models.py b/src/app/website/models.py similarity index 100% rename from src/website/models.py rename to src/app/website/models.py diff --git a/src/website/templates/about.html b/src/app/website/templates/about.html similarity index 100% rename from src/website/templates/about.html rename to src/app/website/templates/about.html diff --git a/src/website/templates/base.html b/src/app/website/templates/base.html similarity index 100% rename from src/website/templates/base.html rename to src/app/website/templates/base.html diff --git a/src/website/templates/donate.html b/src/app/website/templates/donate.html similarity index 100% rename from src/website/templates/donate.html rename to src/app/website/templates/donate.html diff --git a/src/website/templates/home.html b/src/app/website/templates/home.html similarity index 100% rename from src/website/templates/home.html rename to src/app/website/templates/home.html diff --git a/src/website/views.py b/src/app/website/views.py similarity index 100% rename from src/website/views.py rename to src/app/website/views.py diff --git a/src/app/wsgi.py b/src/app/wsgi.py new file mode 100644 index 0000000..6aaacd3 --- /dev/null +++ b/src/app/wsgi.py @@ -0,0 +1,7 @@ +from __future__ import annotations +from website import create_app + +app = create_app() + +if __name__ == "__main__": + app.run() diff --git a/src/gunicorn/gunicorn.conf.py b/src/gunicorn/gunicorn.conf.py new file mode 100644 index 0000000..484a42e --- /dev/null +++ b/src/gunicorn/gunicorn.conf.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +import multiprocessing + +bind = "0.0.0.0:8000" +workers = multiprocessing.cpu_count() * 2 + 1 + +loglevel = "debug" diff --git a/src/gunicorn/gunicorn.sh b/src/gunicorn/gunicorn.sh new file mode 100644 index 0000000..544a446 --- /dev/null +++ b/src/gunicorn/gunicorn.sh @@ -0,0 +1 @@ +gunicorn -c ./gunicorn.conf.py 'wsgi:app' diff --git a/src/nginx/conf/nginx.conf b/src/nginx/conf/nginx.conf new file mode 100644 index 0000000..b6288bb --- /dev/null +++ b/src/nginx/conf/nginx.conf @@ -0,0 +1,31 @@ +upstream hello_flask { + server webapp:8000; +} + +server { + listen 80; + + server_name localhost; + + location / { + return 301 https://$server_name:8443$request_uri; + } +} + +server { + listen 443 ssl; + + server_name localhost; + + ssl_certificate /etc/nginx/ssl/localhost.crt; + ssl_certificate_key /etc/nginx/ssl/localhost.key; + + location / { + proxy_pass http://hello_flask; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + } +} diff --git a/src/nginx/keys/localhost.crt b/src/nginx/keys/localhost.crt new file mode 100644 index 0000000..46d6191 --- /dev/null +++ b/src/nginx/keys/localhost.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDzCCAfegAwIBAgIULnBEtFpdd7D+gcpvj8YjAq+R6D8wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDYyNjExMjkyMloXDTI0MDcy +NjExMjkyMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA5ePEgmz6KUOO9ZvwcB3aF68eT3COg1d3KYcCHjBnJhWX +DaYK3y/cFVOtDF2N4SQa6U4Jr3FYpWzbpApFZEKa9lKli6KGrCwbKyZTEyJL0SBt +bj4CirUS4t/iIlRJUs0i0Hu5q/Y4sGsPdziwuWXz2sU9Fh0U+F8gVFhkR8q74LbN +aheZrisk6hjIpLOVNO6UDACWLQlfddI7E7mzbkrX1k6SMKNZkhfESOdIVsGjK+9M +z75U8AJMHnkRcKRzQYBlm2WF5YlMqGTJAENU18a5LwRBpo3VVHWEdP9h1AzlcRbQ +mzjuSoxMCkU4RLSAL4JscnDbUQZLDQBZWYwSH8UxJQIDAQABo1kwVzAUBgNVHREE +DTALgglsb2NhbGhvc3QwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMB +MB0GA1UdDgQWBBSsOUZ7RzAKyhfR65lRdnLNU3vgNzANBgkqhkiG9w0BAQsFAAOC +AQEAXrqB98vtH/NcNyL0ABl0Fk65OplJ0TVAgAnZcoTtfYTP1xzL4x1P2XJuqDmJ +mRMzv6eKrslROgfDT9YXmWAnSQqJPV+VE1h9jU6917tLQPlRMLvc/nVMQ94lV6dc +CVebjQTkhfKzCQULzXN5E6cXf3dt9PkVovTmcCnIvJ74/uP2bD0WhPexTnUkk7Qj +lLlgkvud0nFpKqinStXFxrOygkJFt893b6fbHsC9RiFqhxs+NfGGJrb628cQVLUV +ayzkxmt0U6kX4LE93mcoH+8u63IkjdV4PJvd/xU41Dsqp8rOJAzIOp8LTeqFFfU0 +/XRlYscYIpdNGlT1SH1FE4e5Vw== +-----END CERTIFICATE----- diff --git a/src/nginx/keys/localhost.key b/src/nginx/keys/localhost.key new file mode 100644 index 0000000..c60d790 --- /dev/null +++ b/src/nginx/keys/localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDl48SCbPopQ471 +m/BwHdoXrx5PcI6DV3cphwIeMGcmFZcNpgrfL9wVU60MXY3hJBrpTgmvcVilbNuk +CkVkQpr2UqWLooasLBsrJlMTIkvRIG1uPgKKtRLi3+IiVElSzSLQe7mr9jiwaw93 +OLC5ZfPaxT0WHRT4XyBUWGRHyrvgts1qF5muKyTqGMiks5U07pQMAJYtCV910jsT +ubNuStfWTpIwo1mSF8RI50hWwaMr70zPvlTwAkweeRFwpHNBgGWbZYXliUyoZMkA +Q1TXxrkvBEGmjdVUdYR0/2HUDOVxFtCbOO5KjEwKRThEtIAvgmxycNtRBksNAFlZ +jBIfxTElAgMBAAECggEABSvKlk0hkr8LHq7gyYIqZIuoXgy/7+gOQqK0+KffEhtn +N+6LDQ/UXq3F/+K0180fm9gzszy/S+KhzX6mUUXcRXvWGcjQnbEqSp4EkrLGoNAe +wLLoDLsGTzsjqOEGJd9+ZSZ7UTPAfQYTetDizMYke5XMiiGiVfSR026KPEEtA7Ye +BhjeiLZEjpuYtYsaYquXmzUL24gdmrCRNuyqRtaUeLGs5S9kyTnBILRvr8GkUnUe +hNEoZ2hw766kViWzkBvjlbNN4GVbtdENKKA//oRE7nAQl6UaobN4mvdh8Z1oiAYu +hADgyPXz1H4+Li67usGf59gMGJH/3foeeGkXcoFS0QKBgQD+NOeXm+8ebsVyzqfz +IWmikZO7a1wlMe70Lv1KhnUOtW3Tyw+OaVKPb8m/g8IB08v0T/glQH/oD2Gk0AUl +lwl1NM8jlE9ZlJaL9EF/cJfWx/8rjznBg6T0BR2q1pJAFUvtJ/mzMNPS2b4q1qQt +Npm99dcyDqM6yaAKvwy2KssTnQKBgQDngvJdqVJoyx+WlgcDvXJt/xoYcwO23odm +Wxq6jY7hMLaO9GOqorqNTgEwdP4rYnsazc1xBvkGo4atd5qFLq8kONGsuUOn6UWh +2mo1tSreznZkfW8P4mTmugkXvyloIInRYvh5JzIZT6hOgaxQDQVHKn9VZCz66EuX +0uznYxYxKQKBgFwIbVxfUSgUdJnHJdkJXMRFrlWpXdf9hwSSypMjsNedaeDG4J/v +k7tofoM+wYuF0Y5nMXDTNDug7foMcgCU+RCdCO1ZsYy+Fe8fhGMOMXrKN6Denstn +zN2nyIDkZFidHTsEQQvV/qqUuJur0A6qeOjkS3/M+t26x518Y67EOXelAoGBAImY +e0INi6w65XhTjLG9XBBiKPlVCmUalzDPfvBXiA7xK9+FAuN8uhGXxf8t2Y6hhnck +0DCYK1O1xyq8RjtXxsJpfr0Ak2RtsXQD41Iubd9kqFsLbgHr1XqIITVa6Vo41JB9 +GR6wnAcNIAQg7+/X/UYRzQJMeqtZeuwucZ0IeD0ZAoGBAPxB+pN01TuBYyzi0Eta +jqWgdhzTbLugMy69q8d/+jz7csuExysGV5gchbcS5p0BrbhjVWajEiddpVI7xaa3 +MuCBjXhbnfxeeOWcd7NzEF9GVWDkZGuzpUlCbjJAB37nxCb+5QZ841vArj19qGAn +VR332b7GuTySlRE3HYHstCre +-----END PRIVATE KEY-----