Skip to content

Commit afb5bd4

Browse files
committed
downgrade to Vultr Regular Performance 1vCPU/1GB and tighten resource limits
Switch from High Frequency 2vCPU/2GB ($18/mo) to Regular Performance 1vCPU/1GB ($5/mo). Tighten HAProxy rate limits from 100/50/30 RPM to 60/30/15 RPM with lower global RPS thresholds (200/300 instead of 300/500). Reduce maxconn, socket buffers, file descriptor limits, and Docker resource settings to fit within 1GB RAM constraints. Update all user-facing content and translations across 14 locales.
1 parent 22516e0 commit afb5bd4

25 files changed

Lines changed: 157 additions & 157 deletions

File tree

deploy/INSTALL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ This triggers the full pipeline. Monitor progress under the **Actions** tab in t
6464

6565
### Infrastructure Details
6666

67-
- **VPS**: Vultr High Frequency (`vhf-2c-2gb`), Debian 13, region `dfw` (Dallas)
67+
- **VPS**: Vultr Regular Performance (`vc2-1c-1gb`), Debian 13, region `dfw` (Dallas)
6868
- **Firewall**: SSH open, HTTPS restricted to Cloudflare IP ranges
6969
- **Deployment**: Blue-green with HAProxy traffic switching
7070
- **First deploy**: Automatically applies base OS hardening (UFW, fail2ban, sysctl tuning) and installs Docker

deploy/ansible/roles/app/templates/docker-compose.yml.j2

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ services:
1515
restart: unless-stopped
1616
ulimits:
1717
nofile:
18-
soft: 65536
19-
hard: 65536
18+
soft: 32768
19+
hard: 32768
2020
sysctls:
21-
net.core.somaxconn: "16384"
21+
net.core.somaxconn: "4096"
2222
net.ipv4.tcp_tw_reuse: "1"
2323
networks:
2424
- internal
@@ -38,8 +38,8 @@ services:
3838
restart: unless-stopped
3939
ulimits:
4040
nofile:
41-
soft: 65536
42-
hard: 65536
41+
soft: 32768
42+
hard: 32768
4343
networks:
4444
- internal
4545

@@ -58,8 +58,8 @@ services:
5858
restart: unless-stopped
5959
ulimits:
6060
nofile:
61-
soft: 65536
62-
hard: 65536
61+
soft: 32768
62+
hard: 32768
6363
networks:
6464
- internal
6565

deploy/ansible/roles/app/templates/haproxy.cfg.j2

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
global
22
log stderr local0 err
3-
maxconn 10000
4-
# Performance tuning for high-throughput
3+
maxconn 4096
4+
# Performance tuning (sized for 1 vCPU / 1 GB RAM)
55
tune.bufsize 16384
66
tune.maxrewrite 1024
7-
tune.http.maxhdr 128
7+
tune.http.maxhdr 101
88
tune.comp.maxlevel 1
99
# TLS configuration optimized for Cloudflare Origin CA ECC certificates
1010
ssl-default-bind-curves prime256v1:X25519:secp384r1
@@ -18,7 +18,7 @@ defaults
1818
option httplog
1919
option dontlog-normal
2020
option http-keep-alive
21-
maxconn 10000
21+
maxconn 4096
2222
timeout connect 5s
2323
timeout client 30s
2424
timeout server 30s
@@ -63,12 +63,12 @@ frontend http_in
6363
# Track global request rate (per second)
6464
http-request track-sc1 str(global) table global_rate_tracking
6565

66-
# Tier 3: global >= 500 RPS -> limit each IP to 30 RPM
67-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 500 } { sc_http_req_rate(0) gt 30 }
68-
# Tier 2: global >= 300 RPS -> limit each IP to 50 RPM
69-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0) gt 50 }
70-
# Tier 1: default -> limit each IP to 100 RPM
71-
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 100 }
66+
# Tier 3: global >= 300 RPS -> limit each IP to 15 RPM
67+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0) gt 15 }
68+
# Tier 2: global >= 200 RPS -> limit each IP to 30 RPM
69+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 200 } { sc_http_req_rate(0) gt 30 }
70+
# Tier 1: default -> limit each IP to 60 RPM
71+
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 60 }
7272

7373
# Block /health from external access
7474
acl is_health path /health
@@ -115,12 +115,12 @@ frontend https_in
115115
# Track global request rate (per second)
116116
http-request track-sc1 str(global) table global_rate_tracking
117117

118-
# Tier 3: global >= 500 RPS -> limit each IP to 30 RPM
119-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 500 } { sc_http_req_rate(0,http_in) gt 30 }
120-
# Tier 2: global >= 300 RPS -> limit each IP to 50 RPM
121-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0,http_in) gt 50 }
122-
# Tier 1: default -> limit each IP to 100 RPM
123-
http-request deny deny_status 429 if { sc_http_req_rate(0,http_in) gt 100 }
118+
# Tier 3: global >= 300 RPS -> limit each IP to 15 RPM
119+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0,http_in) gt 15 }
120+
# Tier 2: global >= 200 RPS -> limit each IP to 30 RPM
121+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 200 } { sc_http_req_rate(0,http_in) gt 30 }
122+
# Tier 1: default -> limit each IP to 60 RPM
123+
http-request deny deny_status 429 if { sc_http_req_rate(0,http_in) gt 60 }
124124

125125
# Block /health from external access
126126
acl is_health path /health
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# System-wide file descriptor limits for web service (10k concurrent connections)
2-
* soft nofile 65536
3-
* hard nofile 65536
4-
root soft nofile 65536
5-
root hard nofile 65536
1+
# System-wide file descriptor limits for web service (1 vCPU / 1 GB RAM)
2+
* soft nofile 32768
3+
* hard nofile 32768
4+
root soft nofile 32768
5+
root hard nofile 32768

deploy/ansible/roles/base/templates/sysctl.conf.j2

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# Network performance tuning for web service (10k concurrent connections)
1+
# Network performance tuning for web service (1 vCPU / 1 GB RAM)
22

3-
# Socket buffer sizes
4-
net.core.rmem_max = 8388608
5-
net.core.wmem_max = 8388608
6-
net.core.rmem_default = 262144
7-
net.core.wmem_default = 262144
3+
# Socket buffer sizes (reduced for 1 GB RAM)
4+
net.core.rmem_max = 4194304
5+
net.core.wmem_max = 4194304
6+
net.core.rmem_default = 131072
7+
net.core.wmem_default = 131072
88

9-
# TCP buffer auto-tuning
10-
net.ipv4.tcp_rmem = 4096 87380 8388608
11-
net.ipv4.tcp_wmem = 4096 65536 8388608
9+
# TCP buffer auto-tuning (reduced for 1 GB RAM)
10+
net.ipv4.tcp_rmem = 4096 65536 4194304
11+
net.ipv4.tcp_wmem = 4096 32768 4194304
1212

13-
# Connection backlog
14-
net.core.somaxconn = 16384
15-
net.core.netdev_max_backlog = 16384
16-
net.ipv4.tcp_max_syn_backlog = 16384
13+
# Connection backlog (reduced for 1 vCPU)
14+
net.core.somaxconn = 4096
15+
net.core.netdev_max_backlog = 4096
16+
net.ipv4.tcp_max_syn_backlog = 4096
1717

1818
# TCP connection reuse and timeout
1919
net.ipv4.tcp_tw_reuse = 1
@@ -44,16 +44,16 @@ net.ipv4.tcp_sack = 1
4444

4545
# SYN flood protection
4646
net.ipv4.tcp_syncookies = 1
47-
net.ipv4.tcp_max_tw_buckets = 200000
47+
net.ipv4.tcp_max_tw_buckets = 65536
4848

49-
# File descriptor limits
50-
fs.file-max = 131072
51-
fs.nr_open = 131072
49+
# File descriptor limits (reduced for 1 GB RAM)
50+
fs.file-max = 65536
51+
fs.nr_open = 65536
5252

53-
# VM tuning
54-
vm.swappiness = 10
55-
vm.dirty_ratio = 15
53+
# VM tuning (increased swappiness slightly for 1 GB RAM)
54+
vm.swappiness = 30
55+
vm.dirty_ratio = 10
5656
vm.dirty_background_ratio = 5
5757

5858
# Connection tracking (for iptables/fail2ban)
59-
net.netfilter.nf_conntrack_max = 32768
59+
net.netfilter.nf_conntrack_max = 16384

deploy/ansible/roles/docker/tasks/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
dest: /etc/systemd/system/docker.service.d/override.conf
5959
content: |
6060
[Service]
61-
LimitNOFILE=65536
62-
LimitNPROC=8192
61+
LimitNOFILE=32768
62+
LimitNPROC=4096
6363
LimitCORE=infinity
6464
owner: root
6565
group: root
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
{
22
"log-driver": "json-file",
33
"log-opts": {
4-
"max-size": "10m",
5-
"max-file": "3"
4+
"max-size": "5m",
5+
"max-file": "2"
66
},
77
"live-restore": true,
88
"default-ulimits": {
99
"nofile": {
1010
"Name": "nofile",
11-
"Hard": 65536,
12-
"Soft": 65536
11+
"Hard": 32768,
12+
"Soft": 32768
1313
},
1414
"nproc": {
1515
"Name": "nproc",
16-
"Hard": 8192,
17-
"Soft": 8192
16+
"Hard": 4096,
17+
"Soft": 4096
1818
}
1919
},
20-
"default-shm-size": "256M"
20+
"default-shm-size": "64M"
2121
}

deploy/terraform/variables.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ variable "region" {
1616
}
1717

1818
variable "plan" {
19-
description = "Vultr plan ID (High Frequency 2 vCPU / 2 GB)"
19+
description = "Vultr plan ID (Regular Performance 1 vCPU / 1 GB)"
2020
type = string
21-
default = "vhf-2c-2gb"
21+
default = "vc2-1c-1gb"
2222
}
2323

2424
variable "os_id" {

haproxy/haproxy.cfg

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ frontend https_in
4747
# Track global request rate (per second)
4848
http-request track-sc1 str(global) table global_rate_tracking
4949

50-
# Tier 3: global >= 500 RPS -> limit each IP to 30 RPM
51-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 500 } { sc_http_req_rate(0) gt 30 }
52-
# Tier 2: global >= 300 RPS -> limit each IP to 50 RPM
53-
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0) gt 50 }
54-
# Tier 1: default -> limit each IP to 100 RPM
55-
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 100 }
50+
# Tier 3: global >= 300 RPS -> limit each IP to 15 RPM
51+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 300 } { sc_http_req_rate(0) gt 15 }
52+
# Tier 2: global >= 200 RPS -> limit each IP to 30 RPM
53+
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 200 } { sc_http_req_rate(0) gt 30 }
54+
# Tier 1: default -> limit each IP to 60 RPM
55+
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 60 }
5656

5757
# Block /health from external access
5858
acl is_health path /health

locales/ar.po

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ msgstr "أرسل طلبًا إلى نقطة النهاية <code>/json</code>،
8787
msgid "Can I call your service programmatically?"
8888
msgstr "هل يمكنني استدعاء خدمتكم برمجيًا؟"
8989

90-
msgid "Sure, but please respect our rate limits. Normally it's 100 RPM, and under heavy load we may drop it to 50 or 30 RPM."
91-
msgstr "بالتأكيد، لكن يرجى الالتزام بحدود المعدل. عادةً يكون 100 طلبًا في الدقيقة، وتحت الحمل الثقيل قد نخفضه إلى 50 أو 30 طلبًا في الدقيقة."
90+
msgid "Sure, but please respect our rate limits. Normally it's 60 RPM, and under heavy load we may drop it to 30 or 15 RPM."
91+
msgstr "بالتأكيد، لكن يرجى الالتزام بحدود المعدل. عادةً يكون 60 طلبًا في الدقيقة، وتحت الحمل الثقيل قد نخفضه إلى 30 أو 15 طلبًا في الدقيقة."
9292

9393
msgid "The API is meant for manual use or small projects. If your site uses our API to look up visitor IPs, please use a message queue so requests don't block. If your project has high traffic or needs low latency, you're better off using our open source offline database: <a href=\"https://github.com/NetworkCats/Merged-IP-Data\">Merged IP Database</a>. That's actually what this project uses under the hood."
9494
msgstr "واجهة برمجة التطبيقات مخصصة للاستخدام اليدوي أو المشاريع الصغيرة. إذا كان موقعك يستخدم واجهة برمجة التطبيقات الخاصة بنا للبحث عن عناوين IP للزوار، يرجى استخدام قائمة انتظار الرسائل حتى لا تتعطل الطلبات. إذا كان مشروعك يتعامل مع حركة مرور عالية أو يحتاج إلى زمن استجابة منخفض، فمن الأفضل استخدام قاعدة بياناتنا المحلية مفتوحة المصدر: <a href=\"https://github.com/NetworkCats/Merged-IP-Data\">Merged IP Database</a>. هذا في الواقع ما يستخدمه هذا المشروع داخليًا."
@@ -123,11 +123,11 @@ msgstr "تجربة المستخدم أيضًا أفضل من معظم مواقع
123123
msgid "Is this service reliable?"
124124
msgstr "هل هذه الخدمة موثوقة؟"
125125

126-
msgid "The whole thing is written in Rust, so performance is great. It can handle L7 DDoS traffic and stay up fine. It runs on a 2 core 2 GB VPS, which is already more than enough. The only thing that could cause real trouble is a large scale L7 DDoS, but we have Cloudflare in front of us."
127-
msgstr "كل شيء مكتوب بلغة Rust، لذا الأداء ممتاز. يمكنه التعامل مع هجمات DDoS من الطبقة السابعة والاستمرار في العمل. يعمل على خادم VPS ثنائي النواة بذاكرة 2 غيغابايت، وهو أكثر من كافٍ. الشيء الوحيد الذي قد يسبب مشكلة حقيقية هو هجوم DDoS واسع النطاق من الطبقة السابعة، لكن لدينا Cloudflare أمامنا."
126+
msgid "The whole thing is written in Rust, so performance is great. It can handle L7 DDoS traffic and stay up fine. It runs on a 1 core 1 GB VPS, which is already more than enough. The only thing that could cause real trouble is a large scale L7 DDoS, but we have Cloudflare in front of us."
127+
msgstr "كل شيء مكتوب بلغة Rust، لذا الأداء ممتاز. يمكنه التعامل مع هجمات DDoS من الطبقة السابعة والاستمرار في العمل. يعمل على خادم VPS أحادي النواة بذاكرة 1 غيغابايت، وهو أكثر من كافٍ. الشيء الوحيد الذي قد يسبب مشكلة حقيقية هو هجوم DDoS واسع النطاق من الطبقة السابعة، لكن لدينا Cloudflare أمامنا."
128128

129-
msgid "It costs me $18.00/month to run, which is pretty cheap. I'm not going to shut it down over hosting costs anytime soon, and there won't be any ads."
130-
msgstr "تكلفة التشغيل 18.00 دولار شهريًا، وهو رخيص جدًا. لن أوقفها بسبب تكاليف الاستضافة، ولن تكون هناك أي إعلانات."
129+
msgid "It costs me $5.00/month to run, which is pretty cheap. I'm not going to shut it down over hosting costs anytime soon, and there won't be any ads."
130+
msgstr "تكلفة التشغيل 5.00 دولار شهريًا، وهو رخيص جدًا. لن أوقفها بسبب تكاليف الاستضافة، ولن تكون هناك أي إعلانات."
131131

132132
msgid "This service is not going to rug pull on you."
133133
msgstr "هذه الخدمة لن تختفي فجأة."

0 commit comments

Comments
 (0)