Skip to content

fix: add HTTPS/SSL configuration to Nginx template#979

Merged
A1L13N merged 5 commits into
alphaonelabs:mainfrom
Ananya44444:err
Mar 1, 2026
Merged

fix: add HTTPS/SSL configuration to Nginx template#979
A1L13N merged 5 commits into
alphaonelabs:mainfrom
Ananya44444:err

Conversation

@Ananya44444
Copy link
Copy Markdown
Contributor

@Ananya44444 Ananya44444 commented Feb 27, 2026

Related issues

Fixes #977

Checklist

  • Did you run the pre-commit? (If not, your PR will most likely not pass — please ensure it passes pre-commit)
  • Did you test the change? (Ensure you didn’t just prompt the AI and blindly commit — test the code and confirm it works)
  • [/] Added screenshots to the PR description (if applicable)

Summary by CodeRabbit

  • New Features
    • Enforces HTTPS by redirecting all HTTP traffic to HTTPS while preserving ACME challenge handling.
    • Adds an HTTPS server with TLSv1.2/1.3 and a strong cipher configuration with server preference.
    • Uses Let's Encrypt certificates when a domain is provided; falls back to self-signed certificates otherwise.
    • Applies domain/www resolution logic so hostnames resolve correctly.
    • Serves static and media assets and proxies the application (including WebSocket support) securely.

Copilot AI review requested due to automatic review settings February 27, 2026 09:12
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Missing Open Issue Link

This pull request does not reference any open GitHub issue via the Development section.

PRs must be linked to an open issue using GitHub’s "Development" section (on the right sidebar).

How to fix this:

  • Go to the PR page.
  • Use the "Link issue" option in the Development section.
  • Select an appropriate open issue.

This PR will be automatically closed. You can reopen it after linking an open issue.

Thank you!

@github-actions github-actions Bot added the files-changed: 1 PR changes 1 file label Feb 27, 2026
@github-actions github-actions Bot closed this Feb 27, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 27, 2026

Walkthrough

Adds an HTTP server (port 80) that serves ACME challenges and 308-redirects other requests to HTTPS; adds an HTTPS server (port 443) with conditional server_name, conditional Let's Encrypt vs snakeoil certs, TLSv1.2/1.3 and strong ciphers, plus static/media and proxied app (WebSocket) handling.

Changes

Cohort / File(s) Summary
Nginx HTTP/HTTPS config
ansible/nginx-http.conf.j2
Adds HTTP server on port 80 serving ACME challenges and returning a 308 redirect for other requests; adds HTTPS server on port 443 with conditional server_name (adds www. when domain_name has exactly one dot and doesn't already start with www.; falls back when no domain_name), conditional cert paths (Let's Encrypt under /etc/letsencrypt/live/{{ domain_name }} or snakeoil), enforces TLSv1.2/v1.3 and a strong cipher suite, retains /static/ and /media/ aliases and reverse-proxy (including WebSocket) for application root.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Nginx80 as Nginx (port 80)
    participant Nginx443 as Nginx (port 443)
    participant Certs as Certificates
    participant App as Backend App

    Client->>Nginx80: HTTP request
    alt ACME challenge path
        Nginx80->>Client: Serve ACME challenge
    else Other paths
        Nginx80->>Client: 308 Redirect to https://$host$request_uri
        Client->>Nginx443: HTTPS request
        Nginx443->>Certs: Select certs (Let's Encrypt if domain_name provided, else snakeoil)
        Nginx443->>Client: TLS handshake + response
        alt Static or media request
            Nginx443->>Client: Serve /static/ or /media/
        else App route (including WebSocket)
            Nginx443->>App: Proxy request / upgrade websocket
            App->>Nginx443: Response
            Nginx443->>Client: Response
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The linked issue lacks specific technical details about errors; the PR adds HTTPS/SSL configuration but without visibility to actual error logs, alignment is inconclusive. Provide error logs or specific details about the runtime errors in issue #977 to verify the HTTPS/SSL configuration resolves them.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding HTTPS/SSL configuration to the Nginx template, which is confirmed by all changes in the file.
Out of Scope Changes check ✅ Passed All changes in the Nginx template directly relate to adding HTTPS/SSL configuration and related server logic, with no extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds HTTPS support to the Ansible-managed Nginx config so the app can be served over TLS and HTTP traffic is redirected to HTTPS.

Changes:

  • Redirect all HTTP (port 80) traffic to HTTPS while still allowing ACME challenge paths.
  • Add an HTTPS (port 443) server block with TLS settings and proxying to the app.

Comment thread ansible/nginx-http.conf.j2
Comment thread ansible/nginx-http.conf.j2
Comment thread ansible/nginx-http.conf.j2 Outdated
Comment thread ansible/nginx-http.conf.j2 Outdated
@A1L13N A1L13N reopened this Feb 27, 2026
@github-actions github-actions Bot closed this Feb 27, 2026
@A1L13N A1L13N reopened this Feb 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ansible/nginx-http.conf.j2`:
- Around line 54-55: Add standard TLS hardening adjacent to the existing
ssl_protocols and ssl_ciphers settings: enable server cipher preference by
setting ssl_prefer_server_ciphers on; configure SSL session caching and timeout
via ssl_session_cache and ssl_session_timeout to improve performance; and add a
Strict-Transport-Security response header (add_header Strict-Transport-Security
...) with an appropriate max-age and includeSubDomains/preload options to
enforce HTTPS. Update the server block where ssl_protocols and ssl_ciphers are
declared (look for the ssl_protocols and ssl_ciphers symbols) to include these
directives and ensure they are applied to HTTPS listeners.
- Around line 52-53: The SSL directives ssl_certificate and ssl_certificate_key
currently interpolate {{ domain_name }} unguarded and will produce invalid paths
when domain_name is unset; update the ansible/nginx-http.conf.j2 template to
wrap those two directives in the same Jinja2 conditional used for server_name
(i.e., only emit ssl_certificate and ssl_certificate_key when domain_name is
defined/non-empty), or alternatively add an assertion in the Ansible playbook to
fail fast if domain_name is undefined (use an assert or fail task) so that
nginx-http.conf.j2 is only rendered when domain_name exists.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e12c98e and 444c35d.

📒 Files selected for processing (1)
  • ansible/nginx-http.conf.j2

Comment thread ansible/nginx-http.conf.j2
Comment thread ansible/nginx-http.conf.j2
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ansible/nginx-http.conf.j2`:
- Line 29: The server_name directive's conditional for adding a www alias is
inconsistent between the HTTP and HTTPS server blocks: update the template so
both server_name occurrences use the same check on domain_name (only append
"www." when domain_name.count('.') == 1 and not domain_name.startswith('www.'))
to ensure the www alias is added only for single-dot domains and not for
multi-level hostnames, preventing unintended TLS name coverage.
- Line 39: The redirect uses an untrusted $host in the line "return 308
https://$host$request_uri;", allowing host-header open redirects; change the
template in ansible/nginx-http.conf.j2 to use a configured canonical host when
available (e.g. domain_name) and only fall back to $host if not set—implement a
Jinja conditional around the existing "return 308 ..." so it emits "return 308
https://<configured canonical host>$request_uri" when domain_name is provided,
otherwise keep the original behavior.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 444c35d and c3e65a9.

📒 Files selected for processing (1)
  • ansible/nginx-http.conf.j2

Comment thread ansible/nginx-http.conf.j2
Comment thread ansible/nginx-http.conf.j2 Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
ansible/nginx-http.conf.j2 (1)

39-39: ⚠️ Potential issue | 🟠 Major

Guard the HTTPS redirect when domain_name is missing.

Line 39 always interpolates {{ domain_name }}. If domain_name is unset/empty, redirect generation becomes invalid (or template rendering can fail), breaking HTTP→HTTPS behavior.

🔧 Proposed fix
         location / {
-            return 308 https://{{ domain_name }}$request_uri;
+            {% if domain_name %}
+            return 308 https://{{ domain_name }}$request_uri;
+            {% else %}
+            return 308 https://$host$request_uri;
+            {% endif %}
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ansible/nginx-http.conf.j2` at line 39, The HTTPS redirect always
interpolates {{ domain_name }} in the return directive (the line with "return
308 https://{{ domain_name }}$request_uri;"), which will break if domain_name is
unset; update the nginx-http.conf.j2 template to guard this: render the redirect
only when domain_name is defined/non-empty, and otherwise either omit the
redirect or fall back to a safe alternative such as using $host (e.g., generate
"return 308 https://$host$request_uri;" when domain_name is missing); wrap the
return directive in a Jinja conditional that checks domain_name before emitting
the domain-based redirect or emits the safe fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@ansible/nginx-http.conf.j2`:
- Line 39: The HTTPS redirect always interpolates {{ domain_name }} in the
return directive (the line with "return 308 https://{{ domain_name
}}$request_uri;"), which will break if domain_name is unset; update the
nginx-http.conf.j2 template to guard this: render the redirect only when
domain_name is defined/non-empty, and otherwise either omit the redirect or fall
back to a safe alternative such as using $host (e.g., generate "return 308
https://$host$request_uri;" when domain_name is missing); wrap the return
directive in a Jinja conditional that checks domain_name before emitting the
domain-based redirect or emits the safe fallback.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3e65a9 and 92ffb37.

📒 Files selected for processing (1)
  • ansible/nginx-http.conf.j2

@A1L13N
Copy link
Copy Markdown
Contributor

A1L13N commented Feb 27, 2026

@coderabbitai can we remove this? location / {
return 308 https://{{ domain_name }}$request_uri;
}

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 27, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the full Nginx configuration file to understand the structure
cat ansible/nginx-http.conf.j2

Length of output: 2457


@A1L13N, no, we cannot remove that location / block. It's the essential mechanism that redirects all HTTP traffic (port 80) to HTTPS (port 443). Without it, users accessing your site via http:// would not be redirected to https://.

However, I spotted a potential issue: The redirect hardcodes {{ domain_name }}, but looking at the rest of the template, there are conditions for when domain_name is not provided (using snakeoil certificates). If domain_name is undefined, this redirect will break.

Suggested fix:

location / {
    {% if domain_name %}
    return 308 https://{{ domain_name }}$request_uri;
    {% else %}
    return 308 https://$host$request_uri;
    {% endif %}
}

Or more simply, always use $host which is the Host header from the request:

location / {
    return 308 https://$host$request_uri;
}

The $host approach is cleaner and works whether domain_name is provided or not, while still redirecting to the exact hostname the user requested.


🧠 Learnings used
Learnt from: A1L13N
Repo: alphaonelabs/alphaonelabs-education-website PR: 342
File: web/migrations/0050_counterstatistic_alter_sessionattendance_status_and_more.py:18-18
Timestamp: 2025-03-30T03:45:48.739Z
Learning: A1L13N prefers to avoid creating separate models for storing calculated statistics and instead suggests calculating stats directly in the view when needed.

Learnt from: A1L13N
Repo: alphaonelabs/alphaonelabs-education-website PR: 342
File: web/migrations/0050_counterstatistic_alter_sessionattendance_status_and_more.py:18-18
Timestamp: 2025-03-30T03:45:48.739Z
Learning: A1L13N prefers to avoid creating separate models for storing calculated statistics and instead suggests calculating stats directly in the view or using caching mechanisms rather than persistent database models.

@A1L13N
Copy link
Copy Markdown
Contributor

A1L13N commented Feb 27, 2026

@coderabbitai why 308?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 27, 2026

Tip

For best results, initiate chat on the files or code changes.

@A1L13N, great question! The 308 Permanent Redirect is the best choice for HTTP→HTTPS redirects because it:

  1. Preserves the HTTP method — Unlike 301 (Moved Permanently), which can change POST requests to GET during the redirect, 308 guarantees that POST stays POST, PUT stays PUT, etc.

  2. Indicates permanence — It tells browsers and search engines "always use HTTPS for this resource going forward," which helps with SEO and allows browsers to cache the redirect.

Comparison:

  • 301 Moved Permanently → ❌ May change POST to GET
  • 302 Found (temporary) → ❌ Temporary + may change method
  • 307 Temporary Redirect → ✅ Preserves method but ❌ temporary
  • 308 Permanent Redirect → ✅ Preserves method + ✅ permanent

This is especially important for:

  • WebSocket upgrades (like your virtual classroom, which likely uses WebSockets)
  • POST requests (forms, API calls)
  • Other non-GET methods (PUT, PATCH, DELETE)

If you used 301 and someone POSTed to http://yoursite.com/api/endpoint, the browser might convert it to a GET request when redirecting to HTTPS, breaking the API call. With 308, the POST is preserved.

TL;DR: 308 is the modern, RFC-compliant way to do permanent HTTPS redirects while preserving the original request method. 🔒


🧠 Learnings used
Learnt from: A1L13N
Repo: alphaonelabs/alphaonelabs-education-website PR: 342
File: web/migrations/0050_counterstatistic_alter_sessionattendance_status_and_more.py:18-18
Timestamp: 2025-03-30T03:45:48.739Z
Learning: A1L13N prefers to avoid creating separate models for storing calculated statistics and instead suggests calculating stats directly in the view when needed.

Learnt from: A1L13N
Repo: alphaonelabs/alphaonelabs-education-website PR: 342
File: web/migrations/0050_counterstatistic_alter_sessionattendance_status_and_more.py:18-18
Timestamp: 2025-03-30T03:45:48.739Z
Learning: A1L13N prefers to avoid creating separate models for storing calculated statistics and instead suggests calculating stats directly in the view or using caching mechanisms rather than persistent database models.

@A1L13N A1L13N merged commit 203c95f into alphaonelabs:main Mar 1, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

files-changed: 1 PR changes 1 file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

We are getting these errors on the virtual classroom. Please fix it.

3 participants