Practical Recommendations for Securing an Nginx Server for a Cryptocurrency Exchange
Installing a currency exchange script on a server running Nginx makes you a potential target for hackers. A vulnerability in the web server configuration can lead to DDoS attacks, theft of funds from hot wallets, or compromise of client data. This guide contains practical steps for hardening your Nginx server before launching a high-risk project.
1. Basic Configuration and Updates
1.1. Current Versions
Always use the latest stable version of Nginx. Outdated versions contain known vulnerabilities.
# For Ubuntu/Debian
sudo apt update && sudo apt upgrade nginx -y
# For CentOS/RHEL
sudo yum update nginx -y
1.2. Hiding the Server Version
Hide Nginx version and OS information in response headers to make life difficult for attackers.
In the /etc/nginx/nginx.conf file, in the http section, add:
server_tokens off;
1.3. Protection from information gathering
Restrict access to sensitive areas that could reveal information about your script.
In your site's configuration (in the server block), add:
# Block access to configuration, backup, and login files
location ~ /(\.env|\.git|config|backups|sql|admin|/\.) {
deny all;
return 404;
}
# Block access to executable script files (php, pl, py) in certain directories
location ~* ^/(uploads|images|css|js)/.*\.(php|pl|py|jsp|asp)$ {
deny all;
}
2. Configuring SSL and a secure connection
2.1. Using modern protocols and ciphers
Disable outdated and vulnerable protocols (SSLv2, SSLv3, TLS 1.0, TLS 1.1). Use only strong ciphers.
Add the following to the site's configuration file (usually in the server block for port 443):
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
2.2. Mandatory HTTPS redirection
All traffic must go over a secure protocol only.
Add a separate server block for port 80:
server {
listen 80;
server_name your-exchange.com www.your-exchange.com;
return 301 https://$server_name$request_uri;
}
2.3. HTTP Security Headers
Add headers that will protect your site from common attacks such as XSS, clickjacking, and MIME sniffing.
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always;
# Warning! Configure CSP for your script; it may block legitimate resources.
3. Request Limiting and DDoS Protection
3.1. Rate Limiting
This is critically important for API endpoints and login forms to prevent brute-force attacks and some DDoS attacks.
Add the following zones to the http section of nginx.conf:
# Zone for limiting access to the admin panel (10 requests per minute from one IP)
limit_req_zone $binary_remote_addr zone=admin:10m rate=10r/m;
# Zone for limiting requests to the API (60 requests per minute)
limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;
# Zone for all other requests (more lenient limit)
limit_req_zone $binary_remote_addr zone=general:10m rate=120r/m;
Apply zones in the site configuration:
location /admin/login.php {
limit_req zone=admin burst=5 nodelay;
# ... other configuration ...
}
location /api/v1/ {
limit_req zone=api burst=20 nodelay;
# ... other configuration ...
}
location / {
limit_req zone=general burst=40 nodelay;
# ... other configuration ...
}
3.2. Request Size Limitation
Protect against attacks aimed at exhausting server resources.
client_max_body_size 1M;
client_body_timeout 10;
client_header_timeout 10;
4. Access Control and the File System
4.1. Denying Access to Sensitive Files
Explicitly deny access to all files except those that should be public.
location ~* \.(log|sql|tar|gz|key)$ {
deny all;
}
# Deny access to hidden files (starting with a dot)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
4.2. Setting Correct Access Permissions
- Script files must be owned by an unprivileged user (e.g. www-data or nginx).
- File permissions: 644, directory permissions: 755.
- The site's root directory (root) should not have write permissions, except for specific folders (e.g., uploads, tmp, logs).
4.3. IP Blocking (optional, but recommended)
Restrict access to the admin panel to trusted IP addresses only.
location /admin/ {
allow 192.0.2.100; # Your static IP
allow 203.0.113.50; # Your employee's IP
deny all;
# ... other configuration ...
}
5. Monitoring and Logging
5.1. Configuring Log Format
Add more information to the log, including IP address, processing time, and User-Agent.
In the http section of nginx.conf:
log_format main '$remote_addr - $remote_user [$time_local] "$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent" "$http_x_forwarded_for"'
'rt=$request_time uct="$upstream_connect_time"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
5.2. Regular Log Analysis
Use tools like fail2ban to automatically block IP addresses that exhibit suspicious activity (multiple 404 errors, brute-force attempts). Configure it to monitor Nginx logs.
Quick Checklist
- server_tokens off; enabled.
- HTTP to HTTPS redirection configured.
- Only TLS 1.2/1.3 and modern ciphers are used.
- Rate Limiting implemented for /admin and /api.
- Key security headers added (X-Content-Type-Options and others).
- Access to sensitive files (.env, .git, config) is explicitly denied.
- Access to The admin panel is restricted by IP (if possible).
- Permissions for files in the site's root directory are set correctly.
- Logs are enabled and configured to collect detailed information.
Conclusion
Securing Nginx for a cryptocurrency exchange is a multi-layered process that cannot be ignored. The settings presented here create a powerful baseline level of protection capable of mitigating most automated attacks and significantly complicating the lives of targeted attackers.
Important: After making any configuration changes, always test it for errors and only then restart Nginx:
sudo nginx -t && sudo systemctl reload nginx