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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>subh.space</title>
<style>
:root {
--bg-outer: #1d2021;
--bg-inner: #282828;
--fg: #ebdbb2;
--gray: #928374;
--yellow: #fabd2f;
--aqua: #8ec07c;
--blue: #83a598;
--orange: #fe8019;
--line: #3c3836;
}
body {
background-color: var(--bg-outer);
color: var(--fg);
font-family: 'Iosevka Nerd Font Propo';
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
header {
padding: 2.5rem 1rem;
display: flex;
gap: 1.5rem;
justify-content: center;
flex-wrap: wrap;
}
header a {
color: var(--aqua);
text-decoration: none;
font-weight: bold;
}
header a:hover {
text-decoration: underline;
}
.container {
background-color: var(--bg-inner);
width: 90%;
max-width: 750px;
padding: 3rem;
border-radius: 4px;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
}
h1 {
color: var(--yellow);
font-size: 1.8rem;
margin-top: 0;
margin-bottom: 1rem;
line-height: 1.2;
}
h2 {
color: var(--orange);
font-size: 1.3rem;
margin-top: 2rem;
margin-bottom: 0.8rem;
}
p {
line-height: 1.6;
margin-bottom: 1rem;
}
code {
color: var(--blue);
font-family: 'JetBrains Mono', Courier, monospace;
font-size: 0.95rem;
}
pre {
background-color: var(--bg-outer);
padding: 1.2rem;
border-radius: 4px;
border: 1px solid var(--line);
overflow-x: auto;
margin: 1.5rem 0;
}
pre code {
color: var(--blue);
font-size: 0.9rem;
white-space: pre;
}
.comment {
color: var(--gray);
}
.browser-box {
border-left: 3px solid var(--line);
padding-left: 1.5rem;
margin: 1.5rem 0;
}
.browser-title {
color: var(--aqua);
font-weight: bold;
display: block;
margin-bottom: 0.5rem;
}
footer {
margin: 3rem 0;
color: var(--gray);
font-size: 0.85rem;
text-align: center;
}
</style>
</head>
<body>
<header>
<a href="../index.html">home</a>
<a href="https://git.subh.space">git</a>
<a href="https://github.com/5epi0l">github</a>
<a href="https://notes.subh.space">notes</a>
<a href="https://www.hackthebox.com">hackthebox</a>
<a href="https://search.subh.space">search</a>
</header>
<main class="container">
<h1>Self-Hosting searxNG with Docker</h1>
<p>This is a step-by-step guide on how to self-host your own instance of searxNG using docker, with full <strong>TLS</strong> support with certbot. For those of you who are unaware of searxNG, it's a free and open-source privacy-respecting metasearch engine that aggregates the results from multiple search engines for the user. Visiting <a href="https://searx.space">searx.space</a>, you can find public instances of searxNG which are hosted by people. If you also want to do the same, read on.</p>
<p>This guide assumes you're using a debian-based system.</p>
<h2>1. Installing necessary packages</h2>
<p>You need to install a few packages before starting the setup.</p>
<pre><code>sudo apt update && sudo apt upgrade
sudo apt install docker docker-compose nginx python3-certbot python3-certbot-nginx</code></pre>
<h2>2. Setting up</h2>
<p>Download the necessary files for searxNG.</p>
<pre><code>mkdir -p searxng/core-config
cd searxng
curl -fsSL \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example
</code></pre>
<p>Make a <code>.env</code> file with the following contents:
<pre><code>SEARXNG_VERSION=latest
SEARXNG_HOST=[::]
SEARXNG_PORT=8080
</code></pre>
You can use the downloaded <code>docker-compose.yml</code> file or use the modified one below if you face any issues
<pre><code>version: '3.8'
services:
core:
container_name: searxng-core
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}
restart: always
ports:
- "8080:8080"
env_file: ./.env
volumes:
- ./core-config/:/etc/searxng/:Z
- core-data:/var/cache/searxng/
valkey:
container_name: searxng-valkey
image: docker.io/valkey/valkey:9-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: always
volumes:
- valkey-data:/data/
volumes:
core-data:
valkey-data:
</code></pre>
<p>Finally, you can bring up the containers.</p>
<pre><code>docker-compose up -d</pre></code>
<p>If you have followed the tutorial meticulously thus far, you should have an instance of searxNG running on <code>http://yourdomain.com:8080</code> (provided that you've correctly configured the DNS records.)</p>
<p>If you can't access it, make sure there are no firewall rules blocking inbound requests to that port.</p>
<h2>3. Configuring searxNG</h2>
<p>If you want to change the defaults for searxNG, you can do so by editing the file <code>core-config/settings.yml</code>. Configuring involves changing the default search engines, enhancing privacy and all.</p>
<p>Here's a <a href="https://subh.space/configs/searxng-settings.yml">link</a> to my <code>settings.yml</code> incase you want to use it.</p>
<p>When you make a change to your <code>settings.yml</code> file, make sure to restart the containers for the change to take effect.</p>
<pre><code>docker-compose down
docker-compose up -d</code></pre>
<p>It is also a good idea to setup rate limiting for your searxNG instance to reduce bot activities and abuse. To do so, create a file under <code>core-config/</code> with the name <code>limiter.toml</code> and the following as contents.
<pre><code>[botdetection.ip_limit]
link_token = true</code></pre>
<p>Also change the value of <code>limiter</code> to true under the <code>server:</code> block in <code>settings.yml</code>.
<h2>4. Setting up SSL/TLS with certbot and nginx</h2>
<p>Save the following nginx config to <code>/etc/nginx/sites-available/searxng</code></p>
<pre><code>server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}</code></pre>
</p>Create the symlink to tell nginx to use it</p>
<pre><code>sudo ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/</code></pre>
<p>Test the config and reload nginx</p>
<pre><code>sudo nginx -t && sudo systemctl reload nginx</code></pre>
<p>Now, you use certbot to request a certificate for your domain(s) by following the prompts.</p>
<pre><code>certbot --nginx</code></pre>
<p>At the end of it, you should have SSL/TLS setup for your searxNG instance. Visit <code>https://yourdomain.com</code> and you should see your own self-hosted searxNG instance.</p>
</main>
<footer>
© 2026 subh.space
</footer>
</body>
</html>
|