-
-
Notifications
You must be signed in to change notification settings - Fork 234
ansible setup #4598
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
base: main
Are you sure you want to change the base?
ansible setup #4598
Conversation
WalkthroughIntroduces an Ansible-based deployment for a Django project and updates ignore rules. Adds an Ansible playbook and README describing deployment steps, configures system packages, Python environment, database, systemd service (Uvicorn), Nginx proxy, UFW rules, and optional PostgreSQL remote access. Updates .gitignore patterns and adds specific ignored files. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer
participant A as Ansible (Controller)
participant S as Target Server
participant Apt as apt/packages
participant Git as git
participant Py as Python venv/pip
participant DJ as Django manage.py
participant PG as PostgreSQL
participant Sys as systemd (Uvicorn)
participant NX as Nginx
participant UFW as UFW
Dev->>A: ansible-playbook -i inventory.yml playbook.yml
A->>S: Connect via SSH
A->>Apt: Install system packages
A->>S: Create app user and directories
A->>Git: Clone/Update repo on server
A->>Py: Create venv, upgrade pip/setuptools
A->>Py: Install deps (poetry export or install)
A->>S: Write .env.production and symlink .env
A->>DJ: collectstatic, migrate (within project dir)
A->>PG: Ensure service running
A->>PG: Create DB user and database (idempotent)
alt Remote PG enabled
A->>PG: Update postgresql.conf / pg_hba.conf
A->>PG: Restart via handlers
end
A->>Sys: Create/enable systemd service (Uvicorn)
A->>NX: Configure site, enable, disable default
A->>NX: Reload on change
A->>UFW: Allow 22/80/443 (and 5432 if enabled)
A->>UFW: Enable firewall
A-->>Dev: Print deployment summary (URL, PG access)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Pull Request Overview
This PR introduces Ansible automation for deploying the BLT Django application. It provides infrastructure-as-code setup for server provisioning, application deployment, and service configuration.
- Adds complete Ansible playbook for automated Django app deployment
- Configures systemd service with uvicorn ASGI server
- Sets up Nginx reverse proxy with static file serving
Reviewed Changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.
File | Description |
---|---|
ansible/playbook.yml | Main deployment playbook with tasks for system setup, Django deployment, PostgreSQL configuration, and web server setup |
ansible/README.md | Documentation for using the Ansible deployment system |
- Creates a systemd service `gunicorn-blt`. | ||
- Nginx reverse proxies to Gunicorn on port 8000. |
Copilot
AI
Oct 3, 2025
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.
The documentation incorrectly references 'gunicorn-blt' service and Gunicorn server, but the playbook actually creates a 'blt-uvicorn' service using uvicorn ASGI server. Update documentation to match the actual implementation.
- Creates a systemd service `gunicorn-blt`. | |
- Nginx reverse proxies to Gunicorn on port 8000. | |
- Creates a systemd service `blt-uvicorn`. | |
- Nginx reverse proxies to uvicorn (ASGI) server on port 8000. |
Copilot uses AI. Check for mistakes.
content: | | ||
DEBUG=False | ||
ALLOWED_HOSTS=.{{ domain }},{{ domain }},127.0.0.1,localhost | ||
SECRET_KEY={{ lookup('password', '/dev/null', length=64, chars='ascii_letters,digits') }} |
Copilot
AI
Oct 3, 2025
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.
The SECRET_KEY is regenerated on every playbook run because it uses '/dev/null' as the password file. This will invalidate user sessions and potentially cause Django to reject existing signed data. Use a persistent file path like '/tmp/django_secret_key' or generate it once and store it securely.
SECRET_KEY={{ lookup('password', '/dev/null', length=64, chars='ascii_letters,digits') }} | |
SECRET_KEY={{ lookup('password', '{{ app_dir }}/shared/secret_key', length=64, chars='ascii_letters,digits') }} |
Copilot uses AI. Check for mistakes.
loop: | ||
- '22' | ||
- '80' | ||
- '443' | ||
- '5432' |
Copilot
AI
Oct 3, 2025
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.
PostgreSQL port 5432 is opened in the firewall unconditionally, but remote PostgreSQL access is controlled by the 'enable_remote_postgres' variable. The firewall rule should only open port 5432 when remote access is actually enabled to reduce attack surface.
loop: | |
- '22' | |
- '80' | |
- '443' | |
- '5432' | |
loop: "{{ ['22', '80', '443'] + (enable_remote_postgres | bool | ternary(['5432'], [])) }}" |
Copilot uses AI. Check for mistakes.
become_user: postgres | ||
shell: | | ||
psql -tc "SELECT 1 FROM pg_roles WHERE rolname='{{ postgres_db_user }}'" | grep -q 1 || psql -c "CREATE ROLE {{ postgres_db_user }} LOGIN PASSWORD '{{ postgres_db_password }}';" | ||
changed_when: false |
Copilot
AI
Oct 3, 2025
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.
The PostgreSQL password is exposed in the command line and process list. Use the postgresql_user Ansible module instead of shell commands to securely create database users without exposing credentials.
become_user: postgres | |
shell: | | |
psql -tc "SELECT 1 FROM pg_roles WHERE rolname='{{ postgres_db_user }}'" | grep -q 1 || psql -c "CREATE ROLE {{ postgres_db_user }} LOGIN PASSWORD '{{ postgres_db_password }}';" | |
changed_when: false | |
community.postgresql.postgresql_user: | |
name: "{{ postgres_db_user }}" | |
password: "{{ postgres_db_password }}" | |
login: true | |
state: present | |
become_user: postgres |
Copilot uses AI. Check for mistakes.
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.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base
setting
📒 Files selected for processing (3)
.gitignore
(2 hunks)ansible/README.md
(1 hunks)ansible/playbook.yml
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run Tests
- GitHub Check: docker-test
enable_remote_postgres: "{{ enable_remote_postgres | default(true) }}" | ||
pre_tasks: |
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.
Lock down PostgreSQL remote access by default.
enable_remote_postgres
currently defaults to true
and we always open UFW port 5432 plus append a pg_hba
rule for 0.0.0.0/0
. On a fresh run this exposes the database listener to the entire internet with just password auth, which is a critical security regression.
Please make remote access opt‑in (default false
) and gate both the pg_hba
change and the firewall rule behind that flag. Example:
- enable_remote_postgres: "{{ enable_remote_postgres | default(true) }}"
+ enable_remote_postgres: "{{ enable_remote_postgres | default(false) }}"
...
- - name: Open firewall ports
+ - name: Open firewall ports
ufw:
rule: allow
port: "{{ item }}"
loop:
- '22'
- '80'
- '443'
- - '5432'
+ - name: Allow PostgreSQL port when remote access enabled
+ ufw:
+ rule: allow
+ port: '5432'
+ when: enable_remote_postgres | bool
That keeps the database private unless the operator explicitly opts in.
Also applies to: 157-171, 236-244
🤖 Prompt for AI Agents
In ansible/playbook.yml around lines 11-12 (and similarly at 157-171 and
236-244), change the enable_remote_postgres default from true to false and gate
both the UFW rule that opens port 5432 and the pg_hba.conf rule append behind
this flag; update variable definition to default(false), wrap the tasks that add
the pg_hba entry and the ufw rule in when: enable_remote_postgres | bool, and
ensure any handlers or conditionals that reload/restart PostgreSQL only run when
the flag is true so remote access is opt-in and not exposed by default.
- name: Create production env file (.env.production) | ||
copy: | ||
dest: "{{ app_dir }}/current/{{ env_file }}" | ||
owner: "{{ app_user }}" | ||
group: "{{ app_user }}" | ||
mode: '0600' | ||
content: | | ||
DEBUG=False | ||
ALLOWED_HOSTS=.{{ domain }},{{ domain }},127.0.0.1,localhost | ||
SECRET_KEY={{ lookup('password', '/dev/null', length=64, chars='ascii_letters,digits') }} | ||
DATABASE_URL=postgres://{{ postgres_db_user }}:{{ postgres_db_password }}@127.0.0.1:5432/{{ postgres_db_name }} | ||
PORT=8000 | ||
# Add any extra environment variables below | ||
# SENTRY_DSN= | ||
# OPENAI_API_KEY= | ||
notify: Restart app | ||
|
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.
Persist the Django SECRET_KEY instead of regenerating every run.
Using lookup('password', '/dev/null', ...)
creates a brand-new secret on every playbook execution. That forces a service restart each time and invalidates all Django sessions/tokens, even when nothing else changed.
Please persist the generated value (e.g., write it once to a file under {{ app_dir }}/shared/secret_key
and reuse it on subsequent runs) so reruns stay idempotent. Example:
- SECRET_KEY={{ lookup('password', '/dev/null', length=64, chars='ascii_letters,digits') }}
+ SECRET_KEY={{ lookup('password', '{{ app_dir }}/shared/secret_key', length=64, chars='ascii_letters,digits') }}
This keeps the secret stable across deployments while still generating it on first run.
🤖 Prompt for AI Agents
In ansible/playbook.yml around lines 88-104, the SECRET_KEY is being regenerated
on every run using lookup('password', '/dev/null', ...), causing unnecessary
restarts and session invalidation; change the play so it first checks for a
persisted secret at {{ app_dir }}/shared/secret_key, if missing generate a new
secret and write it to that file with owner {{ app_user }} and mode 0600, then
read the secret from that file and insert its value into the .env.production
content (instead of calling lookup each run); ensure the task is idempotent
(only writes when file absent or empty) and that file permissions are secure so
subsequent playbook runs reuse the same SECRET_KEY.
- Creates a systemd service `gunicorn-blt`. | ||
- Nginx reverse proxies to Gunicorn on port 8000. | ||
- Opens ports 22, 80, 443 with UFW. |
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.
Align README with the actual service (Uvicorn, not Gunicorn).
The playbook provisions a systemd unit named blt-uvicorn
that runs uvicorn
. The README still references a gunicorn-blt
service and Gunicorn proxying, which will mislead anyone operating this deployment. Please update the doc to match the playbook.
🤖 Prompt for AI Agents
ansible/README.md lines 21-23: the README mentions a systemd service named
`gunicorn-blt` and that Nginx reverse proxies to Gunicorn on port 8000, but the
playbook actually provisions `blt-uvicorn` and runs Uvicorn; update the three
bullet points to reference the `blt-uvicorn` systemd service, state that Nginx
reverse proxies to Uvicorn (adjust port if different in the playbook, e.g., 8000
or as configured), and ensure any instructions about service names, sockets, or
systemd unit files match the playbook’s filenames and commands; also replace any
remaining “Gunicorn” mentions with “Uvicorn”.
Summary by CodeRabbit
New Features
Documentation
Chores