ソースを参照

feat: add nginx fallback web server for Trojan camouflage

Install and configure nginx on port 8080 as the fallback server
for trojan-go, so non-Trojan HTTPS traffic is served a static
page instead of failing on an empty port

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kotoyuuko 3 週間 前
コミット
3624244f26

+ 1 - 0
group_vars/landing.yml.example

@@ -6,3 +6,4 @@ tls_key_path: "/etc/letsencrypt/live/{{ trojan_domain }}/privkey.pem"
 allowed_ports:
   - 80
   - "{{ trojan_port }}"
+  - "{{ trojan_fallback_port }}"

+ 2 - 0
openspec/changes/archive/2026-04-22-add-nginx-fallback-for-trojan/.openspec.yaml

@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-04-22

+ 32 - 0
openspec/changes/archive/2026-04-22-add-nginx-fallback-for-trojan/design.md

@@ -0,0 +1,32 @@
+## Context
+
+The trojan-go config template at `roles/trojan/templates/trojan-config.json.j2` sets `remote_port: {{ trojan_fallback_port }}` (default 8080). This is the port trojan-go forwards non-authenticated HTTPS traffic to for camouflage. Currently nothing listens on this port, so trojan-go fails to operate correctly.
+
+## Goals / Non-Goals
+
+**Goals:**
+- Provide a working HTTP fallback on port 8080 for trojan-go camouflage
+- Keep the nginx setup minimal — a generic static page, no reverse proxy logic
+
+**Non-Goals:**
+- Full nginx reverse proxy or multi-site configuration
+- Serving the actual Let's Encrypt TLS site on this port (trojan-go handles TLS on 443)
+
+## Decisions
+
+**Add nginx tasks inside the trojan role rather than a separate role**
+
+The nginx fallback is tightly coupled to the trojan deployment — it exists solely as camouflage for trojan-go. Adding tasks to the existing trojan role keeps the relationship clear and avoids an extra role.
+
+**Use a simple inline nginx config, not a full vhost template directory**
+
+The fallback only needs a minimal server block: listen on `trojan_fallback_port`, serve a generic static HTML page. A single `nginx-fallback.conf.j2` template deployed to `/etc/nginx/conf.d/` is sufficient.
+
+**Allow the fallback port through UFW**
+
+The base role handles firewall rules. The landing role already opens port 80 via `allowed_ports`. Add `trojan_fallback_port` to the landing `allowed_ports` list so nginx is reachable.
+
+## Risks / Trade-offs
+
+- [nginx not installed] → Installing nginx adds a dependency; ensure the task installs it before deploying the config
+- [port conflict] → `trojan_fallback_port` is hardcoded as 8080 in defaults; if another service uses this port, nginx will fail to start

+ 24 - 0
openspec/changes/archive/2026-04-22-add-nginx-fallback-for-trojan/proposal.md

@@ -0,0 +1,24 @@
+## Why
+
+The trojan-go service is configured to forward non-Trojan traffic to `remote_port: 8080` as a fallback camouflage web server, but no service is currently listening on port 8080. This causes trojan-go to fail on startup because the fallback port is unreachable.
+
+## What Changes
+
+- Install nginx as the fallback web server listening on `trojan_fallback_port` (8080)
+- Deploy a minimal nginx vhost that serves as HTTPS camouflage (a generic static page)
+- Add a UFW firewall rule to allow traffic on the fallback port
+- Extend the trojan role to manage the nginx fallback
+
+## Capabilities
+
+### New Capabilities
+- `nginx-fallback`: Nginx fallback web server on the landing server for Trojan camouflage
+
+### Modified Capabilities
+<!-- none -->
+
+## Impact
+
+- `roles/trojan/tasks/main.yml` — add nginx installation and configuration tasks
+- `roles/trojan/templates/` — new nginx vhost template
+- `group_vars/landing.yml.example` — document the fallback port variable

+ 22 - 0
openspec/changes/archive/2026-04-22-add-nginx-fallback-for-trojan/specs/nginx-fallback/spec.md

@@ -0,0 +1,22 @@
+## ADDED Requirements
+
+### Requirement: Nginx is installed as a fallback web server for Trojan
+The landing server SHALL have nginx installed and configured to serve a static fallback page on `trojan_fallback_port`.
+
+#### Scenario: Nginx is installed
+- **WHEN** the trojan role runs on a landing server
+- **THEN** the nginx package is installed and available
+
+### Requirement: Nginx serves a camouflage page on the fallback port
+Nginx SHALL be configured with a server block listening on `trojan_fallback_port` that returns a static HTML page, mimicking a generic website for HTTPS camouflage.
+
+#### Scenario: Fallback page is accessible
+- **WHEN** an HTTP request is made to `localhost:trojan_fallback_port`
+- **THEN** nginx returns a 200 response with static HTML content
+
+### Requirement: Fallback port is allowed through UFW
+The `trojan_fallback_port` SHALL be added to the `allowed_ports` list in `group_vars/landing.yml` so the base role opens it through the firewall.
+
+#### Scenario: Firewall allows fallback port
+- **WHEN** the base role configures UFW
+- **THEN** traffic on `trojan_fallback_port` is allowed

+ 13 - 0
openspec/changes/archive/2026-04-22-add-nginx-fallback-for-trojan/tasks.md

@@ -0,0 +1,13 @@
+## 1. Add nginx installation to trojan role
+
+- [x] 1.1 Add task to install nginx package in `roles/trojan/tasks/main.yml`
+- [x] 1.2 Create nginx fallback config template `roles/trojan/templates/nginx-fallback.conf.j2`
+- [x] 1.3 Add task to deploy the nginx config and enable/start nginx
+
+## 2. Open fallback port in firewall
+
+- [x] 2.1 Add `trojan_fallback_port` to `allowed_ports` in `group_vars/landing.yml.example`
+
+## 3. Verify
+
+- [x] 3.1 Run `ansible-playbook site.yml --check --limit landing-server` to verify playbook parses without errors

+ 22 - 0
openspec/specs/nginx-fallback/spec.md

@@ -0,0 +1,22 @@
+## ADDED Requirements
+
+### Requirement: Nginx is installed as a fallback web server for Trojan
+The landing server SHALL have nginx installed and configured to serve a static fallback page on `trojan_fallback_port`.
+
+#### Scenario: Nginx is installed
+- **WHEN** the trojan role runs on a landing server
+- **THEN** the nginx package is installed and available
+
+### Requirement: Nginx serves a camouflage page on the fallback port
+Nginx SHALL be configured with a server block listening on `trojan_fallback_port` that returns a static HTML page, mimicking a generic website for HTTPS camouflage.
+
+#### Scenario: Fallback page is accessible
+- **WHEN** an HTTP request is made to `localhost:trojan_fallback_port`
+- **THEN** nginx returns a 200 response with static HTML content
+
+### Requirement: Fallback port is allowed through UFW
+The `trojan_fallback_port` SHALL be added to the `allowed_ports` list in `group_vars/landing.yml` so the base role opens it through the firewall.
+
+#### Scenario: Firewall allows fallback port
+- **WHEN** the base role configures UFW
+- **THEN** traffic on `trojan_fallback_port` is allowed

+ 5 - 0
roles/trojan/handlers/main.yml

@@ -4,3 +4,8 @@
     name: trojan-go
     daemon_reload: yes
     state: restarted
+
+- name: restart nginx
+  ansible.builtin.systemd:
+    name: nginx
+    state: restarted

+ 52 - 0
roles/trojan/tasks/main.yml

@@ -118,6 +118,58 @@
     mode: "0644"
   notify: restart trojan
 
+- name: Install nginx for Trojan fallback
+  ansible.builtin.apt:
+    name:
+      - nginx
+    state: present
+
+- name: Deploy nginx fallback config
+  ansible.builtin.template:
+    src: nginx-fallback.conf.j2
+    dest: /etc/nginx/conf.d/trojan-fallback.conf
+    owner: root
+    group: root
+    mode: "0644"
+  notify:
+    - restart nginx
+
+- name: Create fallback web root
+  ansible.builtin.file:
+    path: /var/www/trojan-fallback
+    state: directory
+    owner: www-data
+    group: www-data
+    mode: "0755"
+
+- name: Deploy fallback index page
+  ansible.builtin.copy:
+    content: |
+      <!DOCTYPE html>
+      <html>
+      <head><title>Welcome</title></head>
+      <body><h1>Welcome</h1></body>
+      </html>
+    dest: /var/www/trojan-fallback/index.html
+    owner: www-data
+    group: www-data
+    mode: "0644"
+  notify:
+    - restart nginx
+
+- name: Remove default nginx site
+  ansible.builtin.file:
+    path: /etc/nginx/sites-enabled/default
+    state: absent
+  notify:
+    - restart nginx
+
+- name: Enable and start nginx
+  ansible.builtin.systemd:
+    name: nginx
+    enabled: yes
+    state: started
+
 - name: Enable and start trojan-go service
   ansible.builtin.systemd:
     name: trojan-go

+ 11 - 0
roles/trojan/templates/nginx-fallback.conf.j2

@@ -0,0 +1,11 @@
+server {
+    listen {{ trojan_fallback_port }} default_server;
+    server_name _;
+
+    root /var/www/trojan-fallback;
+    index index.html;
+
+    location / {
+        try_files $uri $uri/ =404;
+    }
+}