-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnginx.conf.sigil
More file actions
205 lines (180 loc) · 8.04 KB
/
nginx.conf.sigil
File metadata and controls
205 lines (180 loc) · 8.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# This is the template we're using to generate our custom nginx.conf file on Dokku.
# Details of how it works can be found here: https://dokku.com/docs/networking/proxies/nginx/#customizing-the-nginx-configuration
#
# For the Lua functions to work, it is required that Lua be added to Nginx.
# On Ubuntu, this is achieved by running the command below:
# sudo apt install libnginx-mod-http-lua
#
# The central idea of the resulting Nginx conf file is converting URLs containing non-ASCII characters into a format that Ghost understands
# and doing the corresponding redirects. This is necessitated by the fact that Ghost doesn't really have i18n support for URLs and slugs.
#
# Why do all this? So that we can handle Medium URLs on Ghost seamlessly.
#
# This means if a user visits
# https://pesacheck.org/partiellement-faux-le-gouvernement-sénégalais-na-pas-été-dissout-après-les-manifestations-du-19-5a7e55071173
# They get transparently redirected to
# https://pesacheck.org/partiellement-faux-le-gouvernement-s-c3-a9n-c3-a9galais-na-pas--c3-a9t-c3-a9-dissout-apr-c3-a8s-les-manifestations-du-19
# Which is the URL of the post within Ghost
#
# Example conversions:
#
# French
# partiellement-faux-le-gouvernement-sénégalais-na-pas-été-dissout-après-les-manifestations-du-19-5a7e55071173 ->
# partiellement-faux-le-gouvernement-s-c3-a9n-c3-a9galais-na-pas--c3-a9t-c3-a9-dissout-apr-c3-a8s-les-manifestations-du-19
#
# Amharic
# የፈጠራ-ወሬ-የየመን-ሚሳኤል-በእስራኤል-ላይ-ያደረሰውን-ጥቃት-ያሳይሉ-የተባሉት-እነዚህ-ሁለት-ፎቶዎች-የተቀነባበሩ-ናቸው-36aa9b306317 ->
# -e1-8b-a8-e1-8d-88-e1-8c-a0-e1-88-ab--e1-8b-88-e1-88-ac--e1-8b-a8-e1-8b-a8-e1-88-98-e1-8a-95--e1-88-9a-e1-88-b3-e1-8a-a4-e1-88-8d--e1-89-a0-e1-8a-a5-e1-88-b5-e1-88-ab-e1-8a-a4-e1-88-8d-
#
# English
# false-ugandas-education-minister-janet-museveni-has-not-ordered-schools-to-end-their-third-term-4ef52ad31a17 ->
# false-ugandas-education-minister-janet-museveni-has-not-ordered-schools-to-end-their-third-term
#
# Determine if the URL needs conversion by checking if it contains non-ASCII characters.
map $uri $needs_conversion {
~[^\x00-\x7F] "yes";
default "no";
}
# Set up a JSON log format for better structured logging.
log_format json escape=json
'{'
'"timestamp": "$time_iso8601",'
'"client_ip": "$remote_addr",'
'"request_id": "$request_id",'
'"http_method": "$request_method",'
'"http_path": "$uri",'
'"protocol": "$server_protocol",'
'"user_agent": "$http_user_agent",'
'"referer": "$http_referer",'
'"status_code": $status,'
'"bytes_sent": $body_bytes_sent,'
'"request_time_secs": $request_time'
'}';
server {
listen [::]:80;
listen 80;
server_name {{ .NOSSL_SERVER_NAME }};
access_log /var/log/nginx/{{ .APP }}-access.log json;
error_log /var/log/nginx/{{ .APP }}-error.log;
underscores_in_headers off;
client_body_timeout 60s;
client_header_timeout 60s;
keepalive_timeout 75s;
lingering_timeout 5s;
send_timeout 60s;
# Remove the random ID that Medium appends to post URLs. This effectively does the same redirect recommended by Ghost here:
# https://docs.ghost.org/migration/medium#using-custom-domains
# Note: This rewrite happens before the redirect to HTTPS
rewrite "^/(.*)(-[0-9a-f]{10,12})$" /$1 permanent;
location / {
return 301 https://$host:443$request_uri;
}
include {{ .DOKKU_ROOT }}/{{ .APP }}/nginx.conf.d/*.conf;
}
server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
{{ if .SSL_SERVER_NAME }}server_name {{ .SSL_SERVER_NAME }}; {{ end }}
access_log /var/log/nginx/{{ .APP }}-access.log json;
error_log /var/log/nginx/{{ .APP }}-error.log;
ssl_certificate {{ .APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ .APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
client_max_body_size 50m;
client_body_timeout 60s;
client_header_timeout 60s;
keepalive_timeout 75s;
lingering_timeout 5s;
send_timeout 60s;
location / {
gzip on;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
gzip_vary on;
gzip_comp_level 6;
# Check if conversion is needed using the map
access_by_lua_block {
-- First check for Medium ID and remove it before processing
local has_medium_id = string.match(ngx.var.uri, "/(.*)-([%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]?[%x]?)$")
if has_medium_id then
-- Remove Medium ID
local clean_path = string.gsub(ngx.var.uri, "/(.*)-([%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]?[%x]?)$", "/%1")
-- Permanent redirect since the Medium ID doesn't mean much on any other platform
ngx.redirect(clean_path, 301)
return
end
if ngx.var.needs_conversion == "yes" then
local function convert_string(input_str)
-- Split the input string by hyphens
local parts = {}
for part in string.gmatch(input_str, "([^%-]+)") do
table.insert(parts, part)
end
-- Process each part (same as above)
local encoded_parts = {}
for i, part in ipairs(parts) do
-- Convert part to UTF-8 byte sequence and encode
local encoded = ""
for j = 1, #part do
local byte = string.byte(part, j)
if byte < 128 and string.match(string.char(byte), "[%w%-_.~]") then
-- Keep safe ASCII characters as is
encoded = encoded .. string.char(byte)
else
-- For all other bytes except the first one, use the -XX format
if #encoded > 0 then
encoded = encoded .. "-" .. string.format("%02x", byte):lower()
else
encoded = encoded .. string.format("%02x", byte):lower()
end
end
end
table.insert(encoded_parts, encoded)
end
-- Join all parts back with hyphens
local result = table.concat(encoded_parts, "-")
-- Truncate the URL at 185 characters in case it is longer to match what Ghost expects
if #result > 185 then
result = string.sub(result, 1, 185)
end
return result
end
-- Remove leading slash for processing
local original_path = ngx.var.uri
if string.sub(original_path, 1, 1) == "/" then
original_path = string.sub(original_path, 2, -1)
end
local converted_path = convert_string(original_path)
-- Redirect to the converted path
-- Only do a temporary redirect allowing us to revert to ASCII URLs in future
ngx.redirect("/" .. converted_path, 307)
return
end
}
proxy_pass http://{{ .APP }};
http2_push_preload on;
proxy_http_version 1.1;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_buffer_size 4k;
proxy_buffering on;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Request-Start $msec;
}
include {{ .DOKKU_ROOT }}/{{ .APP }}/nginx.conf.d/*.conf;
}
upstream {{ .APP }} {
{{ range .DOKKU_APP_WEB_LISTENERS | split " " }}
server {{ . }};
{{ end }}
}