{"id":51146519,"url":"https://github.com/mxagar/webapp_deployment_guide","last_synced_at":"2026-06-26T03:02:13.863Z","repository":{"id":353342999,"uuid":"1219008154","full_name":"mxagar/webapp_deployment_guide","owner":"mxagar","description":"A guide on how to deploy simple web apps on several cloud services.","archived":false,"fork":false,"pushed_at":"2026-04-23T12:53:30.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-23T14:35:58.769Z","etag":null,"topics":["api","aws","azure","backend","blob-storage","deployment","docker","flask","frontend","hetzner","postgresql","railway","render","terraform","webapp"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mxagar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-23T12:43:09.000Z","updated_at":"2026-04-23T12:55:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mxagar/webapp_deployment_guide","commit_stats":null,"previous_names":["mxagar/webapp_deployment_guide"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/mxagar/webapp_deployment_guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxagar%2Fwebapp_deployment_guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxagar%2Fwebapp_deployment_guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxagar%2Fwebapp_deployment_guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxagar%2Fwebapp_deployment_guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mxagar","download_url":"https://codeload.github.com/mxagar/webapp_deployment_guide/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxagar%2Fwebapp_deployment_guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34801014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","aws","azure","backend","blob-storage","deployment","docker","flask","frontend","hetzner","postgresql","railway","render","terraform","webapp"],"created_at":"2026-06-26T03:02:12.688Z","updated_at":"2026-06-26T03:02:13.841Z","avatar_url":"https://github.com/mxagar.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple Web App Deployment Guide\n\nA guide on how to deploy simple web apps on several cloud services.\n\n## Goal\n\nCreate a small but realistic web application project for learning deployment concepts.\n\nThe focus is **not** machine learning infrastructure. The focus is deploying a conventional app that includes the resources many real applications need:\n\n* a Python backend with Flask\n* a simple frontend with HTML, CSS, and JavaScript\n* a PostgreSQL database\n* blob/object storage\n* an API built with Flask\n* containerization with Docker\n* local orchestration with Docker Compose\n* CI/CD for linting, tests, and deployment\n* separate staging and production environments\n\nML functionality, if present, is treated as just another internal application feature.\n\n\n\n## Project Scope\n\nThis project is meant to teach the deployment and operations fundamentals behind a typical small-to-medium web application.\n\nIt should help answer questions like:\n\n* How do I package an app in Docker?\n* How do I run it locally with its dependencies?\n* How do I deploy it to a managed platform or VPS?\n* How do I separate staging from production?\n* How do I handle database access, file storage, authentication, and background work?\n* How do I set up a basic CI/CD pipeline?\n\nThis architecture is representative of a large class of internal tools, SaaS products, dashboards, CRUD systems, admin portals, and API-backed web apps.\n\n\n\n## Functional Components\n\n### 1. Backend\n\nThe backend is a Flask application written in Python.\n\nResponsibilities:\n\n* serve server-side pages or API endpoints\n* implement business logic\n* connect to PostgreSQL\n* manage authentication\n* interact with blob storage\n* expose HTTP endpoints for the frontend and other clients\n\n### 2. Frontend\n\nThe frontend is intentionally simple:\n\n* HTML\n* CSS\n* JavaScript\n\nIt can either:\n\n* be served by Flask templates, or\n* be built as static assets and served through the same app or reverse proxy\n\nThe goal is not frontend complexity, but deployment clarity.\n\n### 3. SQL Database\n\nUse PostgreSQL as the relational database.\n\nResponsibilities:\n\n* store users\n* store business entities\n* store application state\n* store metadata for uploaded files\n* store job state if needed\n\n### 4. Blob/Object Storage\n\nUse blob/object storage for large files and binary assets.\n\nExamples:\n\n* uploaded documents\n* images\n* exports\n* media files\n* optional model artifacts\n\nImportant principle:\n\n* structured relational data goes into PostgreSQL\n* large binary files go into object storage\n\n### 5. API\n\nThe Flask backend also exposes an API.\n\nExamples:\n\n* authentication endpoints\n* CRUD endpoints\n* file upload/download endpoints\n* status endpoints\n\nThis keeps the architecture simple: one backend, one app, multiple interfaces.\n\n\n\n## Recommended Minimal Architecture\n\n### Version 1: Minimal but realistic\n\nThis is the recommended first version.\n\nComponents:\n\n* **Flask** application\n* **Gunicorn** as the WSGI server\n* **Caddy** as reverse proxy\n* **PostgreSQL**\n* **Object storage**\n* **Flask-Login** for authentication\n* **Dockerfile** for packaging\n* **docker-compose.yaml** for local development\n* **GitHub Actions** for CI/CD\n\nConceptual flow:\n\n```text\nBrowser\n  -\u003e Caddy\n  -\u003e Gunicorn\n  -\u003e Flask app\n  -\u003e PostgreSQL\n  -\u003e Object storage\n```\n\n### Why these choices?\n\n#### Caddy as reverse proxy\n\nCaddy is a good learning choice because it is simpler than Nginx and handles HTTPS very smoothly.\n\nResponsibilities:\n\n* terminates HTTPS\n* forwards requests to Gunicorn/Flask\n* can serve static files\n* can manage headers and routing\n\n#### Gunicorn as app server\n\nGunicorn runs the Flask app in a production-ready way.\n\nResponsibilities:\n\n* runs Flask workers\n* handles incoming requests from the reverse proxy\n\n#### Flask-Login for auth\n\nFlask-Login is a good fit for a classic web app with sessions, login/logout, and protected pages.\n\n\n\n## Extended Architecture\n\n### Version 2: Add realism gradually\n\nOnce the minimal version works, add:\n\n* **Redis**\n* **RQ** for background jobs\n* optional caching through Redis\n* basic monitoring and error tracking\n\nConceptual flow:\n\n```text\nBrowser\n  -\u003e Caddy\n  -\u003e Gunicorn\n  -\u003e Flask app\n      -\u003e PostgreSQL\n      -\u003e Object storage\n      -\u003e Redis\n  -\u003e RQ worker\n      -\u003e Redis\n      -\u003e PostgreSQL\n      -\u003e Object storage\n```\n\n### Why Redis?\n\nRedis is useful once the application needs:\n\n* caching\n* background jobs\n* temporary shared state\n* rate limiting\n* session-related extensions\n\n### Why RQ?\n\nRQ is a simple Python background job system backed by Redis.\n\nIt is a good learning option because it is easier to understand than heavier alternatives.\n\nTypical uses:\n\n* processing uploaded files\n* sending emails\n* generating reports or PDFs\n* slow external API calls\n* long-running tasks that should not block web requests\n\n\n\n## Environments: Local, Staging, Production\n\nA key part of deployment learning is understanding that the same app usually runs in multiple environments.\n\n### 1. Local development\n\nPurpose:\n\n* code locally\n* run the full stack on your machine\n* iterate quickly\n\nTypical setup:\n\n* Docker Compose\n* Flask app\n* PostgreSQL container\n* optional Redis container\n* local object storage emulator or mocked/external storage\n\nCharacteristics:\n\n* fastest feedback loop\n* debug-friendly\n* not publicly exposed\n* developer-oriented configuration\n\n### 2. Staging\n\nPurpose:\n\n* environment for pre-production validation\n* test deployment workflows\n* verify migrations\n* test integrations and secrets handling\n* review features before production\n\nCharacteristics:\n\n* should resemble production closely\n* uses separate database and storage\n* may use smaller resources than production\n* can be deployed automatically from a develop or staging branch\n\nTypical uses:\n\n* manual QA\n* integration testing\n* smoke tests after deployment\n* validating infrastructure changes\n\n### 3. Production\n\nPurpose:\n\n* serve real users\n* run the stable version of the system\n\nCharacteristics:\n\n* real traffic\n* real credentials and secrets\n* separate database and storage from staging\n* stronger monitoring and backup requirements\n* stricter access control\n\n\n\n## Why staging matters\n\nWithout staging, every deployment is effectively a production experiment.\n\nStaging helps you validate:\n\n* infrastructure configuration\n* environment variables\n* reverse proxy setup\n* database migrations\n* authentication flows\n* file upload/download behavior\n* CI/CD deployment logic\n\nIt also teaches an important operational principle:\n\n* **same app, different environment configuration**\n\n\n\n## Configuration Strategy\n\nEach environment should have its own configuration values.\n\nExamples:\n\n* `APP_ENV=local|staging|production`\n* database URL\n* object storage bucket/container name\n* secret keys\n* OAuth credentials if added later\n* Redis URL\n* debug mode\n* allowed hosts / domains\n\nImportant rules:\n\n* never hardcode secrets in source code\n* keep staging and production data isolated\n* use environment variables or a secrets manager\n* use different buckets/containers and databases per environment\n\n\n\n## Suggested Deployment Targets\n\nThe project should focus on these targets:\n\n* **AWS**\n* **Azure**\n* **Render**\n* **Railway**\n* **Hetzner VPS**\n\n### How to think about them\n\n#### Render / Railway\n\nBest for learning deployment quickly with less operational burden.\n\nGood for:\n\n* container deployment\n* managed PostgreSQL\n* simpler developer experience\n* CI/CD from Git\n\n#### AWS / Azure\n\nBest for learning mainstream cloud architecture.\n\nGood for:\n\n* managed app hosting\n* managed Postgres\n* managed blob storage\n* infrastructure-as-code\n* more production-like cloud patterns\n\n#### Hetzner VPS\n\nBest for learning infrastructure more directly.\n\nGood for:\n\n* running Docker Compose yourself\n* configuring reverse proxy yourself\n* managing Linux, certificates, and backups\n* understanding what managed platforms abstract away\n\n\n\n## Infrastructure as Code\n\n### Dockerfile\n\nThe Dockerfile packages the Flask application into a deployable container image.\n\nResponsibilities:\n\n* define Python runtime\n* install dependencies\n* copy source code\n* define startup command\n\n### docker-compose.yaml\n\nDocker Compose is mainly for **local development** and sometimes for VPS deployment.\n\nResponsibilities:\n\n* start the app and its dependencies together\n* define service relationships\n* provide local reproducibility\n\nTypical services:\n\n* app\n* postgres\n* caddy\n* optional redis\n* optional worker\n\n### Terraform\n\nTerraform is appropriate mainly when targeting AWS or Azure, and sometimes other platforms where infrastructure provisioning is useful.\n\nUse it for:\n\n* provisioning app infrastructure\n* provisioning databases\n* provisioning storage resources\n* provisioning networking and DNS-related resources where relevant\n\nFor Render or Railway, Terraform is less central to the learning path, because those platforms abstract away much of the infrastructure.\n\n\n\n## CI/CD\n\nA simple CI/CD pipeline should include:\n\n### Continuous Integration\n\nOn every push or pull request:\n\n* install dependencies\n* run linting\n* run tests\n* optionally build Docker image\n\nSuggested checks:\n\n* formatting\n* linting\n* unit tests\n* import checks\n* maybe type checks later\n\n### Continuous Deployment\n\nOn merge to selected branches:\n\n* deploy to **staging** from a staging/develop branch\n* deploy to **production** from the main branch\n\nBasic pipeline idea:\n\n```text\nPush / Pull Request\n  -\u003e lint\n  -\u003e test\n  -\u003e build image\n  -\u003e deploy to staging or production depending on branch\n```\n\n\n\n## Recommended Libraries and Tools\n\n### Core app\n\n* **Flask**\n* **Gunicorn**\n* **psycopg** or **psycopg2** for PostgreSQL access\n* **SQLAlchemy** or Flask-SQLAlchemy if ORM support is desired\n\n### Reverse proxy\n\n* **Caddy**\n\n### Authentication\n\n* **Flask-Login**\n\n### Optional later additions\n\n* **Redis**\n* **RQ**\n\n### CI/CD\n\n* **GitHub Actions**\n\n\n\n## What this project teaches well\n\nThis project is good for learning:\n\n* app packaging with Docker\n* local orchestration with Docker Compose\n* production serving with Gunicorn\n* reverse proxy concepts\n* environment separation\n* managed vs self-managed deployment options\n* PostgreSQL integration\n* object storage integration\n* authentication basics\n* CI/CD basics\n* gradual extension with caching and background jobs\n\n\n\n## What is intentionally not the focus\n\nThis project is not primarily about:\n\n* microservices\n* Kubernetes\n* high-scale distributed systems\n* advanced frontend frameworks\n* full ML platform design\n* event-driven architecture\n\nThose can be learned later.\n\nThe purpose here is to build a strong, realistic foundation.\n\n\n\n## Recommended Learning Progression\n\n### Phase 1\n\nBuild and run locally:\n\n* Flask app\n* PostgreSQL\n* Caddy\n* Docker Compose\n* simple login\n* file upload to blob storage or a mocked local equivalent\n\n### Phase 2\n\nAdd CI/CD:\n\n* linting\n* tests\n* Docker image build\n* deploy to staging\n\n### Phase 3\n\nAdd production deployment:\n\n* production environment\n* separate secrets\n* separate database and storage\n* monitoring basics\n\n### Phase 4\n\nAdd optional realism:\n\n* Redis\n* RQ worker\n* background jobs\n* cache\n* more robust observability\n\n\n\n## Final Recommendation\n\nFor this project, the most sensible architecture is:\n\n* **Flask** backend\n* simple **HTML/CSS/JS** frontend\n* **PostgreSQL** database\n* **object/blob storage**\n* **Gunicorn** as app server\n* **Caddy** as reverse proxy\n* **Flask-Login** for authentication\n* **Dockerfile** for packaging\n* **docker-compose.yaml** for local development\n* **GitHub Actions** for CI/CD\n* distinct **local**, **staging**, and **production** environments\n* optional later addition of **Redis** and **RQ**\n\nThis gives you a deployment-oriented project that is simple enough to learn from, but realistic enough to reflect how many real applications are structured.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxagar%2Fwebapp_deployment_guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmxagar%2Fwebapp_deployment_guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxagar%2Fwebapp_deployment_guide/lists"}