|
1 | 1 | # Eric Gitangu's Tech Blog |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
2 | 10 | <div align="center"> |
3 | 11 | <a href="https://developer.ericgitangu.com"> |
4 | 12 | <img src="https://developer.ericgitangu.com/_next/image?url=%2Ffavicon.png&w=96&q=75" style="border-radius: 50%" alt="deveric.io logo"/> |
5 | | - <h1 align="center">Eric Gitangu</h1> |
| 13 | + <h2>Eric Gitangu</h2> |
6 | 14 | </a> |
7 | | -A Django-powered blog showcasing insights in technology, cybersecurity, and software development. Built with Python and Django, featuring Azure cloud integration and robust security measures. |
8 | | - |
9 | | -</div> |
10 | | - |
11 | | -## 🚀 Features |
12 | | - |
13 | | -- **Dynamic Content Management**: Built-in Django admin interface for content creation |
14 | | -- **Cloud Storage Integration**: Azure Blob Storage for media and static files |
15 | | -- **Production-Ready**: Configured for production with security best practices |
16 | | -- **PostgreSQL Database**: Robust data storage with PostgreSQL |
17 | | -- **Secure Authentication**: Comprehensive password validation and security middleware |
18 | | -- **Logging System**: Detailed debug logging for monitoring and troubleshooting |
19 | | - |
20 | | -## 🛠️ Tech Stack |
21 | 15 |
|
22 | | -### Backend Framework ⚙️ |
23 | | -- Django 4.x |
24 | | -- Python 3.11 |
25 | | -- WSGI Application Server |
| 16 | +A Django-powered blog showcasing insights in technology, AI, systems architecture, cybersecurity, and software development. |
26 | 17 |
|
27 | | -### Database 🗄️ |
28 | | -- PostgreSQL with psycopg2-binary driver |
29 | | -- Environment-based configuration |
| 18 | +**Live:** [blog.ericgitangu.com](https://blog.ericgitangu.com) |
30 | 19 |
|
31 | | -### Cloud Services ☁️ (Azure) |
32 | | -- Azure Web Apps for hosting |
33 | | -- Azure Blob Storage for static/media files |
34 | | -- Azure Managed Identity authentication |
35 | | -- Azure PostgreSQL database |
36 | | - |
37 | | -## 💾 Storage Configuration |
38 | | -- Whitenoise |
39 | | -- PostgresSQL (Azure flexible) |
40 | | - |
41 | | -### 📊 Monitoring and Logging |
42 | | - |
43 | | -Debug logging configured for production monitoring: |
44 | | -- File handler |
45 | | -- Console handler |
46 | | -- App-level logging - Default DEBUG |
47 | | - |
48 | | -### 🔒 Security Configuration |
49 | | - |
50 | | -- **CSRF Protection**: Configured for production domains |
51 | | -- **Secure Middleware Stack**: |
52 | | - - Security Middleware |
53 | | - - WhiteNoise for static files |
54 | | - - Session Management |
55 | | - - CSRF Protection |
56 | | - - Authentication |
57 | | - - XFrame Options |
58 | | - |
59 | | -### 🚀 Production Deployment |
| 20 | +</div> |
60 | 21 |
|
61 | | -The application uses GitHub Actions for CI/CD to Azure Web Apps. The deployment process includes: |
62 | | -- Automated testing |
63 | | -- Static file collection |
64 | | -- Database migrations |
65 | | -- Zero-downtime deployment |
66 | | -- Azure Blob Storage configuration |
67 | | -- Secure environment variable management |
| 22 | +--- |
68 | 23 |
|
69 | | -For more details, see the deployment workflow in `.github/workflows/main_deveric-blog.yml`. |
| 24 | +## Features |
70 | 25 |
|
71 | | -## 🔗 Connect |
| 26 | +- **Dynamic Content Management**: Built-in Django admin interface for content creation |
| 27 | +- **Fly.io Deployment**: Production hosting with PostgreSQL and persistent volumes |
| 28 | +- **Production-Ready Security**: HTTPS, HSTS, secure cookies, and CSRF protection |
| 29 | +- **PostgreSQL Database**: Robust data storage with connection pooling |
| 30 | +- **WhiteNoise Static Files**: Compressed and cached static file serving |
| 31 | +- **Console Logging**: Streamlined logging for fly.io log aggregation |
| 32 | + |
| 33 | +## Tech Stack |
| 34 | + |
| 35 | +| Category | Technology | |
| 36 | +|----------|------------| |
| 37 | +| **Framework** | Django 5.1 | |
| 38 | +| **Language** | Python 3.11 | |
| 39 | +| **Database** | PostgreSQL (Fly Postgres) | |
| 40 | +| **Static Files** | WhiteNoise | |
| 41 | +| **Media Storage** | Fly Volumes | |
| 42 | +| **Server** | Gunicorn | |
| 43 | +| **Deployment** | Fly.io | |
| 44 | + |
| 45 | +## Architecture |
| 46 | + |
| 47 | +```mermaid |
| 48 | +flowchart TB |
| 49 | + subgraph Client ["Client Layer"] |
| 50 | + Browser[Web Browser] |
| 51 | + Mobile[Mobile Browser] |
| 52 | + end |
| 53 | +
|
| 54 | + subgraph Edge ["Fly.io Edge"] |
| 55 | + LB[Load Balancer] |
| 56 | + SSL[SSL/TLS Termination] |
| 57 | + end |
| 58 | +
|
| 59 | + subgraph App ["Application Layer"] |
| 60 | + subgraph Django ["Django Application"] |
| 61 | + WSGI[Gunicorn WSGI] |
| 62 | + MW[Middleware Stack] |
| 63 | + Views[Views & Templates] |
| 64 | + Admin[Admin Dashboard] |
| 65 | + Models[ORM Models] |
| 66 | + end |
| 67 | +
|
| 68 | + subgraph Static ["Static Files"] |
| 69 | + WN[WhiteNoise] |
| 70 | + CSS[CSS/JS Assets] |
| 71 | + end |
| 72 | + end |
| 73 | +
|
| 74 | + subgraph Data ["Data Layer"] |
| 75 | + PG[(PostgreSQL)] |
| 76 | + Vol[Fly Volume<br>/data/media] |
| 77 | + end |
| 78 | +
|
| 79 | + subgraph Models_Detail ["Data Models"] |
| 80 | + Post[Post] |
| 81 | + Author[Author] |
| 82 | + Tag[Tag] |
| 83 | + Comments[Comments] |
| 84 | + end |
| 85 | +
|
| 86 | + Browser --> LB |
| 87 | + Mobile --> LB |
| 88 | + LB --> SSL |
| 89 | + SSL --> WSGI |
| 90 | + WSGI --> MW |
| 91 | + MW --> Views |
| 92 | + MW --> Admin |
| 93 | + Views --> Models |
| 94 | + Admin --> Models |
| 95 | + Models --> PG |
| 96 | + Views --> WN |
| 97 | + WN --> CSS |
| 98 | + Models -.-> Vol |
| 99 | +
|
| 100 | + Post --> Author |
| 101 | + Post --> Tag |
| 102 | + Comments --> Post |
| 103 | +
|
| 104 | + style Django fill:#092E20,color:#fff |
| 105 | + style PG fill:#336791,color:#fff |
| 106 | + style Edge fill:#7C3AED,color:#fff |
| 107 | +``` |
| 108 | + |
| 109 | +### Component Interaction Flow |
| 110 | + |
| 111 | +```mermaid |
| 112 | +sequenceDiagram |
| 113 | + participant U as User |
| 114 | + participant F as Fly.io Edge |
| 115 | + participant G as Gunicorn |
| 116 | + participant D as Django |
| 117 | + participant P as PostgreSQL |
| 118 | + participant V as Volume |
| 119 | +
|
| 120 | + U->>F: HTTPS Request |
| 121 | + F->>G: Forward Request |
| 122 | + G->>D: WSGI Handler |
| 123 | +
|
| 124 | + alt Static Asset |
| 125 | + D->>D: WhiteNoise serves |
| 126 | + D-->>U: Static file |
| 127 | + else Blog Post |
| 128 | + D->>P: Query posts |
| 129 | + P-->>D: Post data |
| 130 | + D->>V: Fetch media |
| 131 | + V-->>D: Image files |
| 132 | + D-->>U: Rendered HTML |
| 133 | + else Admin Action |
| 134 | + D->>D: Auth check |
| 135 | + D->>P: CRUD operation |
| 136 | + P-->>D: Confirmation |
| 137 | + D-->>U: Admin response |
| 138 | + end |
| 139 | +``` |
| 140 | + |
| 141 | +## Local Development |
| 142 | + |
| 143 | +### Prerequisites |
| 144 | +- Python 3.11+ |
| 145 | +- PostgreSQL (or use SQLite for local dev) |
| 146 | + |
| 147 | +### Setup |
| 148 | + |
| 149 | +```bash |
| 150 | +# Clone the repository |
| 151 | +git clone https://github.com/ericgitangu/blog.git |
| 152 | +cd blog |
| 153 | + |
| 154 | +# Create virtual environment |
| 155 | +python -m venv venv |
| 156 | +source venv/bin/activate # On Windows: venv\Scripts\activate |
| 157 | + |
| 158 | +# Install dependencies |
| 159 | +pip install -r requirements.txt |
| 160 | + |
| 161 | +# Set environment variables |
| 162 | +export SECRET_KEY="your-secret-key" |
| 163 | +export DEBUG="True" |
| 164 | +export DBNAME="blog_dev" |
| 165 | +export DBUSER="postgres" |
| 166 | +export DBPASS="password" |
| 167 | +export DBHOST="localhost" |
| 168 | +export DBPORT="5432" |
| 169 | + |
| 170 | +# Run migrations |
| 171 | +python manage.py migrate |
| 172 | + |
| 173 | +# Create superuser |
| 174 | +python manage.py createsuperuser |
| 175 | + |
| 176 | +# Run development server |
| 177 | +python manage.py runserver |
| 178 | +``` |
| 179 | + |
| 180 | +## Deployment to Fly.io |
| 181 | + |
| 182 | +### Prerequisites |
| 183 | +- [Fly CLI](https://fly.io/docs/hands-on/install-flyctl/) |
| 184 | +- Fly.io account |
| 185 | + |
| 186 | +### Deploy |
| 187 | + |
| 188 | +```bash |
| 189 | +# Authenticate |
| 190 | +fly auth login |
| 191 | + |
| 192 | +# Create app and Postgres |
| 193 | +fly apps create deveric-blog |
| 194 | +fly postgres create --name deveric-blog-db --region iad |
| 195 | +fly postgres attach deveric-blog-db --app deveric-blog |
| 196 | + |
| 197 | +# Create volume for media files |
| 198 | +fly volumes create blog_data --region iad --size 1 --app deveric-blog |
| 199 | + |
| 200 | +# Set secrets |
| 201 | +fly secrets set SECRET_KEY="$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')" --app deveric-blog |
| 202 | +fly secrets set DEBUG="False" --app deveric-blog |
| 203 | + |
| 204 | +# Deploy |
| 205 | +fly deploy --app deveric-blog |
| 206 | + |
| 207 | +# Create superuser |
| 208 | +fly ssh console --app deveric-blog |
| 209 | +python manage.py create_superuser --username egitangu --email admin@ericgitangu.com --password yourpassword |
| 210 | +``` |
| 211 | + |
| 212 | +### Custom Domain |
| 213 | + |
| 214 | +```bash |
| 215 | +fly certs add blog.ericgitangu.com --app deveric-blog |
| 216 | +fly ips list --app deveric-blog |
| 217 | +# Add A/AAAA records in your DNS provider |
| 218 | +``` |
| 219 | + |
| 220 | +## Project Structure |
| 221 | + |
| 222 | +``` |
| 223 | +blog/ |
| 224 | +├── blog/ # Django project settings |
| 225 | +│ ├── settings.py # Configuration (Fly.io aware) |
| 226 | +│ ├── urls.py # URL routing |
| 227 | +│ └── wsgi.py # WSGI entry point |
| 228 | +├── portfolio/ # Main blog app |
| 229 | +│ ├── models.py # Post, Author, Tag, Comments |
| 230 | +│ ├── views.py # ListView, DetailView |
| 231 | +│ ├── admin.py # Admin customization |
| 232 | +│ └── templates/ # HTML templates |
| 233 | +├── Dockerfile # Multi-stage production build |
| 234 | +├── fly.toml # Fly.io configuration |
| 235 | +└── requirements.txt # Python dependencies |
| 236 | +``` |
72 | 237 |
|
73 | | -- **Website**: [developer.ericgitangu.com](https://developer.ericgitangu.com) |
74 | | -- **LinkedIn**: [Eric Gitangu](https://linkedin.com/in/ericgitangu) |
75 | | -- **Azure Blog**: [deveric-blog.azurewebsites.net](https://deveric-blog.azurewebsites.net) |
| 238 | +## Security |
76 | 239 |
|
77 | | -## 📄 License |
| 240 | +- HTTPS enforced via Fly.io |
| 241 | +- HSTS with 1-year max-age |
| 242 | +- Secure session and CSRF cookies |
| 243 | +- Password validation policies |
| 244 | +- XFrame options protection |
78 | 245 |
|
79 | | -This project is licensed under the MIT License. |
| 246 | +## Connect |
| 247 | + |
| 248 | +- **Portfolio**: [developer.ericgitangu.com](https://developer.ericgitangu.com) |
| 249 | +- **LinkedIn**: [linkedin.com/in/ericgitangu](https://linkedin.com/in/ericgitangu) |
| 250 | +- **GitHub**: [github.com/ericgitangu](https://github.com/ericgitangu) |
| 251 | +- **Blog**: [blog.ericgitangu.com](https://blog.ericgitangu.com) |
| 252 | + |
| 253 | +## License |
| 254 | + |
| 255 | +This project is licensed under the MIT License. |
0 commit comments