-
-
Notifications
You must be signed in to change notification settings - Fork 177
Fixes #655 ansible mods #656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [defaults] | ||
| inventory = hosts | ||
| pipelining = True | ||
| # host_key_checking = False # use default secure behavior (commented to fall back to default) | ||
| interpreter_python = /usr/bin/python3 | ||
|
|
||
| [ssh_connection] | ||
| retries = 3 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/bin/bash | ||
| set -e | ||
| # Change to script directory | ||
| cd "$(dirname "$0")" | ||
|
|
||
| # ─── Load env file from project root if present ──────────────────────────── | ||
| PROJECT_ROOT="$(cd .. && pwd)" | ||
| if [[ -f "$PROJECT_ROOT/.env" ]]; then | ||
| # shellcheck disable=SC1091 | ||
| set -a | ||
| source "$PROJECT_ROOT/.env" | ||
| set +a | ||
| fi | ||
|
|
||
| # ─── VPS connection details ─────────────────────────────────────────────── | ||
| VPS_IP="${VPS_IP:-}" | ||
| VPS_USER="${VPS_USER:-root}" | ||
| VPS_PASSWORD="${VPS_PASSWORD:-}" | ||
|
|
||
| if [[ -z "$VPS_IP" ]]; then | ||
| echo "❌ VPS_IP not set (export or add to .env)." >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Forward any extra args to ansible-playbook | ||
| EXTRA_ARGS=("$@") | ||
|
|
||
| ANSIBLE_CMD=(ansible-playbook -i "${VPS_IP}," -u "$VPS_USER" playbook.yml) | ||
|
|
||
| if [[ -n "$VPS_PASSWORD" ]]; then | ||
| ANSIBLE_CMD+=(--extra-vars "ansible_password=${VPS_PASSWORD}") | ||
| else | ||
| ANSIBLE_CMD+=(--ask-pass) | ||
| fi | ||
|
|
||
| exec "${ANSIBLE_CMD[@]}" "${EXTRA_ARGS[@]}" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [Unit] | ||
| Description={{ project_name }} website | ||
| After=network.target | ||
|
|
||
| [Service] | ||
| User={{ vps_user }} | ||
| Group={{ vps_user }} | ||
| WorkingDirectory=/home/{{ vps_user }}/{{ project_name }} | ||
| Environment="PATH=/home/{{ vps_user }}/{{ project_name }}/venv/bin" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Django application requires environment variables from the You should use the |
||
| ExecStart=/home/{{ vps_user }}/{{ project_name }}/venv/bin/gunicorn \ | ||
| web.asgi:application -w 4 -k uvicorn.workers.UvicornWorker \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The number of gunicorn workers is hardcoded to 4. This may not be optimal for different server specifications. It's better to make this configurable via an Ansible variable to allow for easier tuning. A common formula for the number of workers is |
||
| --timeout 120 \ | ||
| -b 127.0.0.1:{{ app_port }} | ||
| Restart=always | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| # Django Core Settings | ||
| SECRET_KEY="{{ secret_key }}" | ||
| DEBUG="{{ debug }}" | ||
| ENVIRONMENT="production" | ||
|
|
||
| ALLOWED_HOSTS="{{ allowed_hosts }}" | ||
| CSRF_TRUSTED_ORIGINS="{{ csrf_trusted_origins }}" | ||
|
|
||
| # Database configuration (Production PostgreSQL) | ||
| DB_NAME="{{ db_name }}" | ||
| DB_USER="{{ db_user }}" | ||
| DB_PASSWORD="{{ db_password }}" | ||
| DB_HOST="localhost" | ||
| DB_PORT="5432" | ||
|
|
||
| # Static files | ||
| STATIC_ROOT="/home/{{ vps_user }}/{{ project_name }}/staticfiles" | ||
|
|
||
| # Email Configuration | ||
| {% if sendgrid_api_key %} | ||
| SENDGRID_API_KEY="{{ sendgrid_api_key }}" | ||
| {% endif %} | ||
| {% if sendgrid_password %} | ||
| SENDGRID_PASSWORD="{{ sendgrid_password }}" | ||
| {% endif %} | ||
| {% if email_from %} | ||
| EMAIL_FROM="{{ email_from }}" | ||
| {% endif %} | ||
|
|
||
| # Slack webhook | ||
| {% if slack_webhook_url %} | ||
| SLACK_WEBHOOK_URL="{{ slack_webhook_url }}" | ||
| {% endif %} | ||
|
|
||
| # Stripe configuration | ||
| {% if stripe_secret_key %} | ||
| STRIPE_SECRET_KEY="{{ stripe_secret_key }}" | ||
| {% endif %} | ||
| {% if stripe_publishable_key %} | ||
| STRIPE_PUBLISHABLE_KEY="{{ stripe_publishable_key }}" | ||
| {% endif %} | ||
| {% if stripe_webhook_secret %} | ||
| STRIPE_WEBHOOK_SECRET="{{ stripe_webhook_secret }}" | ||
| {% endif %} | ||
| {% if stripe_connect_webhook_secret %} | ||
| STRIPE_CONNECT_WEBHOOK_SECRET="{{ stripe_connect_webhook_secret }}" | ||
| {% endif %} | ||
|
|
||
| # Security & Encryption | ||
| {% if message_encryption_key %} | ||
| MESSAGE_ENCRYPTION_KEY="{{ message_encryption_key }}" | ||
| {% endif %} | ||
|
|
||
| # Admin Configuration | ||
| {% if admin_url %} | ||
| ADMIN_URL="{{ admin_url }}" | ||
| {% endif %} | ||
|
|
||
| # Google Cloud Storage Configuration | ||
| {% if gs_bucket_name %} | ||
| GS_BUCKET_NAME="{{ gs_bucket_name }}" | ||
| {% endif %} | ||
| {% if gs_project_id %} | ||
| GS_PROJECT_ID="{{ gs_project_id }}" | ||
| {% endif %} | ||
| {% if service_account_file %} | ||
| SERVICE_ACCOUNT_FILE="{{ service_account_file }}" | ||
| {% endif %} | ||
|
|
||
| # Django Debug (separate from DEBUG) | ||
| {% if django_debug %} | ||
| DJANGO_DEBUG="{{ django_debug }}" | ||
| {% endif %} | ||
|
|
||
| # Redis Configuration | ||
| {% if redis_url %} | ||
| REDIS_URL="{{ redis_url }}" | ||
| {% endif %} | ||
|
|
||
| # Cookie security overrides (for staging without HTTPS) | ||
| CSRF_COOKIE_SECURE="{{ csrf_cookie_secure }}" | ||
| SESSION_COOKIE_SECURE="{{ session_cookie_secure }}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| user www-data; | ||
| worker_processes auto; | ||
| pid /run/nginx.pid; | ||
| include /etc/nginx/modules-enabled/*.conf; | ||
|
|
||
| events { | ||
| worker_connections 768; | ||
| } | ||
|
|
||
| http { | ||
| sendfile on; | ||
| tcp_nopush on; | ||
| tcp_nodelay on; | ||
| keepalive_timeout 65; | ||
| types_hash_max_size 2048; | ||
|
|
||
| include /etc/nginx/mime.types; | ||
| default_type application/octet-stream; | ||
|
|
||
| access_log /var/log/nginx/access.log; | ||
| error_log /var/log/nginx/error.log; | ||
|
|
||
| gzip on; | ||
|
|
||
| server { | ||
| listen 80 default_server; | ||
| {% if domain_name %} | ||
| server_name {{ domain_name }}{% if domain_name and not domain_name.startswith('www.') %} www.{{ domain_name }}{% endif %}; | ||
| {% else %} | ||
| server_name _; | ||
| {% endif %} | ||
|
|
||
| location /.well-known/acme-challenge/ { | ||
| root /var/www/html; | ||
| } | ||
|
|
||
| location /static/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/staticfiles/; | ||
| } | ||
|
|
||
| location /media/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/media/; | ||
| } | ||
|
|
||
| location / { | ||
| proxy_pass http://127.0.0.1:{{ app_port }}; | ||
| # WebSocket support | ||
| proxy_http_version 1.1; | ||
| proxy_set_header Upgrade $http_upgrade; | ||
| proxy_set_header Connection "upgrade"; | ||
| proxy_set_header Host $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; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| user www-data; | ||
| worker_processes auto; | ||
| pid /run/nginx.pid; | ||
| include /etc/nginx/modules-enabled/*.conf; | ||
|
|
||
| events { | ||
| worker_connections 768; | ||
| # multi_accept on; | ||
| } | ||
|
|
||
| http { | ||
| sendfile on; | ||
| tcp_nopush on; | ||
| tcp_nodelay on; | ||
| keepalive_timeout 65; | ||
| types_hash_max_size 2048; | ||
|
|
||
| include /etc/nginx/mime.types; | ||
| default_type application/octet-stream; | ||
|
|
||
| ssl_protocols TLSv1.2 TLSv1.3; | ||
| ssl_prefer_server_ciphers on; | ||
|
|
||
| access_log /var/log/nginx/access.log; | ||
| error_log /var/log/nginx/error.log; | ||
|
|
||
| gzip on; | ||
|
|
||
| # Disable gzip for SSE endpoints | ||
| gzip_disable "MSIE [1-6]\."; | ||
|
|
||
| {% if enable_https_redirect == "True" and domain_name %} | ||
| server { | ||
| listen 80 default_server; | ||
| server_name {{ domain_name }}{% if domain_name and not domain_name.startswith('www.') %} www.{{ domain_name }}{% endif %}; | ||
|
|
||
| # This block is for certbot http-01 challenge | ||
| location /.well-known/acme-challenge/ { | ||
| root /var/www/html; | ||
| } | ||
|
|
||
| location / { | ||
| return 301 https://$host$request_uri; | ||
| } | ||
| } | ||
|
|
||
| server { | ||
| listen 443 ssl http2; | ||
| server_name {{ domain_name }}{% if domain_name and not domain_name.startswith('www.') %} www.{{ domain_name }}{% endif %}; | ||
|
|
||
| # SSL configuration managed by Certbot | ||
| ssl_certificate /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem; | ||
| ssl_certificate_key /etc/letsencrypt/live/{{ domain_name }}/privkey.pem; | ||
| include /etc/letsencrypt/options-ssl-nginx.conf; | ||
| ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; | ||
|
|
||
| location /static/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/staticfiles/; | ||
| } | ||
|
|
||
| location /media/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/media/; | ||
| } | ||
|
|
||
| # Special handling for SSE endpoints (admin logs) | ||
| location ~ ^/admin-[^/]+/logs/$ { | ||
| proxy_pass http://127.0.0.1:{{ app_port }}; | ||
| proxy_set_header Host $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; | ||
|
|
||
| # SSE-specific settings | ||
| proxy_set_header Connection ''; | ||
| proxy_http_version 1.1; | ||
| proxy_buffering off; | ||
| proxy_cache off; | ||
| proxy_read_timeout 24h; | ||
| proxy_send_timeout 24h; | ||
|
|
||
| # Disable gzip for SSE | ||
| gzip off; | ||
|
|
||
| # Add SSE headers | ||
| add_header Cache-Control 'no-cache, no-store, must-revalidate'; | ||
| add_header Pragma 'no-cache'; | ||
| add_header Expires '0'; | ||
| add_header X-Accel-Buffering 'no'; | ||
| } | ||
|
|
||
| location / { | ||
| proxy_pass http://127.0.0.1:{{ app_port }}; | ||
| # WebSocket support | ||
| proxy_http_version 1.1; | ||
| proxy_set_header Upgrade $http_upgrade; | ||
| proxy_set_header Connection "upgrade"; | ||
| proxy_set_header Host {{ domain_name | default('alphaonelabs.com') }}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoding the Using the Nginx variable The same issue is present on line 131. |
||
| 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; | ||
|
|
||
| # Standard proxy settings | ||
| proxy_buffering on; | ||
| proxy_buffer_size 4k; | ||
| proxy_buffers 8 4k; | ||
| } | ||
| } | ||
| {% else %} | ||
| server { | ||
| listen 80 default_server; | ||
| {% if domain_name %} | ||
| server_name {{ domain_name }}{% if domain_name and not domain_name.startswith('www.') %} www.{{ domain_name }}{% endif %}; | ||
| {% else %} | ||
| server_name _; | ||
| {% endif %} | ||
|
|
||
| location /static/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/staticfiles/; | ||
| } | ||
|
|
||
| location /media/ { | ||
| alias /home/{{ vps_user }}/{{ project_name }}/media/; | ||
| } | ||
|
|
||
| location / { | ||
| proxy_pass http://127.0.0.1:{{ app_port }}; | ||
| # WebSocket support | ||
| proxy_http_version 1.1; | ||
| proxy_set_header Upgrade $http_upgrade; | ||
| proxy_set_header Connection "upgrade"; | ||
| proxy_set_header Host {{ domain_name | default('alphaonelabs.com') }}; | ||
| 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; | ||
| } | ||
| } | ||
| {% endif %} | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing a password on the command line via
--extra-varsis a major security vulnerability. The password will be visible in the system's process list to other users on the same machine.It's highly recommended to use SSH key-based authentication instead of passwords. If passwords are required, the existing
--ask-passis a much safer alternative as it uses a secure prompt.