分享下我的 nas 安全方案

1 天前
 happyxhw101
  1. 物理机直接安装 ubuntu, 所有应用都部署在 docker
  2. ssh 只允许密钥登录, 禁止 root 用户登录
  3. 所有访问( http, tcp)都通过 nginx 代理, ufw 只暴露固定的几个端口, nginx 开启 https 证书
  4. nginx 配置 geolite2, 禁止任何 国外 ip 访问, 异常访问基本都是国外 ip
  5. fail2ban 自动封禁所有 nginx 日志里面国外 ip
  6. 不安装 1panel,宝塔等任何 web 管理工具, 直接 ssh 到机器上命令行管理

分享下我的 nginx 配置

load_module "modules/ngx_http_geoip2_module.so";
load_module "modules/ngx_stream_geoip2_module.so";

worker_processes 4;

error_log /var/log/nginx/nginx_error.log;
error_log /var/log/nginx/nginx_error.log notice;
error_log /var/log/nginx/nginx_error.log info;

pid /var/log/nginx/nginx.pid;

events {
    worker_connections 1024;
}


http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
      auto_reload 24h;
      $geoip_country_code  default=Unknown source=$remote_addr country iso_code;
      $geoip_country_name  country  names  en;
    }
    geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
      auto_reload 24h;
      $geoip_city   default=Unknown city names en;
    }

    map $geoip_country_code $allowed_country {
        default no;
        CN yes;
    }

    map $remote_addr $allowed {
        default $allowed_country;
        127.0.0.1 yes;
        ~^192\.168\.\\d+\.\\d+$ yes;
        ~^172\.16\.0\.\\d+$ yes;
        ~^172\.17\.\\d+\.\\d+$ yes;
    }

    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' "";
    }

    log_format json_analytics escape=json '{'
    '"timestamp": "$msec", ' # request unixtime in seconds with a milliseconds resolution
    '"request_id": "$request_id", ' # the unique request id
    '"request_length": "$request_length", ' # request length (including headers and body)
    '"body_bytes_sent": "$body_bytes_sent", '
    '"remote_addr": "$remote_addr", ' # client IP
    '"time_iso8601": "$time_iso8601", '
    '"request_uri": "$request_uri", ' # full path and arguments if the request
    '"code": "$status", ' # response status code
    '"http_host": "$http_host", ' # the request Host: header
    '"server_name": "$server_name", ' # the name of the vhost serving the request
    '"request_time": "$request_time", ' # request processing time in seconds with msec resolution
    '"upstream": "$upstream_addr", ' # upstream backend server for proxied requests
    '"request_method": "$request_method", ' # request method
    '"allowed": "$allowed", '
    '"geoip_country_code": "$geoip_country_code", '
    '"geoip_country_name": "$geoip_country_name", '
    '"geoip_city": "$geoip_city"'
    '}';

    access_log /var/log/nginx/access.log json_analytics;
    error_log /var/log/nginx/error.log warn;

    set_real_ip_from 0.0.0.0/0;
    real_ip_header X-Real-IP;
    real_ip_recursive on;

    sendfile on;
    server_tokens off;
    keepalive_timeout 65;

    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    proxy_buffering off;
    proxy_buffers 4 128k;
    proxy_buffer_size 256k;
    proxy_busy_buffers_size 256k;



    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:-LOW:!aNULL:!eNULL;

    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/xxx.cc.key;


    include /etc/nginx/conf.d/*.conf;

}


stream {

    geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
      auto_reload 24h;
      $geoip_country_code  default=Unknown source=$remote_addr country iso_code;
      $geoip_country_name  country  names  en;
    }
    geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
      auto_reload 24h;
      $geoip_city   default=Unknown city names en;
    }



    map $geoip_country_code $allowed_country {
        default no;
        CN yes;
    }

    map $remote_addr $allowed {
        default $allowed_country;
        127.0.0.1 yes;
        ~^192\.168\.\\d+\.\\d+$ yes;
        ~^172\.16\.0\.\\d+$ yes;
        ~^172\.17\.\\d+\.\\d+$ yes;
    }

    log_format json_analytics escape=json '{'
    '"timestamp": "$msec", ' # request unixtime in seconds with a milliseconds resolution
    '"connection": "$connection", ' # connection serial number
    '"pid": "$pid", ' # process pid
    '"remote_addr": "$remote_addr", ' # client IP
    '"remote_port": "$remote_port", ' # client port
    '"time_iso8601": "$time_iso8601", ' # local time in the ISO 8601 standard format
    '"upstream": "$upstream_addr", '
    '"protocol": "$protocol", '
    '"allowed": "$allowed", '
    '"request_method": "STREAM", '
    '"geoip_country_code": "$geoip_country_code", '
    '"geoip_country_name": "$geoip_country_name", '
    '"geoip_city": "$geoip_city"'
    '}';

    access_log /var/log/nginx/access.log json_analytics;
    error_log /var/log/nginx/error.log warn;

    include /etc/nginx/stream.d/*.conf;
}

ssh 代理

map $allowed $ssh_server {
    yes ssh;
}

upstream ssh {
    server  192.168.5.1:1234;
}

server {
    listen    5678;
    listen [::]:5678;
    proxy_pass $ssh_server;
    proxy_connect_timeout 30s;
    proxy_timeout 60s;

    ssl_preread on;
}

http 代理

server {
    server_name x.x.com;
    listen 1233 ssl;
    listen [::]:1233 ssl;

    http2 on;
    charset "utf-8";

    if ($allowed != yes) {
        return 404;
    }

    error_page 497 =307 https://$host:$server_port$request_uri;

    client_max_body_size 512M;
    proxy_buffering off;


    set $backend "http://192.168.5.1:1234";
    include /etc/nginx/conf.d/basic/no_log.conf;

    location / {
        proxy_redirect off;
        proxy_set_header Host $host:$server_port;
        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_pass $backend;
    }

}

1290 次点击
所在节点    NAS
19 条回复
xingheng
22 小时 32 分钟前
这就叫专业.jpg
swiftg
22 小时 28 分钟前
不对公众提供网络服务,只服务自己和有限的几个人的话,完全不用暴露任何端口到公网
wonderfulcxm
22 小时 7 分钟前
你这个也防不了飞牛的路径穿越,还是得加个 waf 。
dilidilid
22 小时 4 分钟前
@wonderfulcxm nginx 在 docker 里,只要不是把根目录挂上去了就算穿越也只能在 docker 里面玩
abc6666
21 小时 58 分钟前
我都是飞牛前面套了一个 WAF 。就可以了。
wwd179
21 小时 58 分钟前
我用 tailscale 组私网。nas 只对公网暴露 tailscale 端口。
有些要对外的服务用 docker 运行 nginx 这些反代。
wonderfulcxm
21 小时 56 分钟前
@dilidilid 如果是飞牛,我理解没错的话,要用 fn connect 要 nginx 反代到宿主机的 5666 或者 5667 端口。无论是不是 docker ,加 waf 是过滤,nginx 就纯是转发了
yinmin
21 小时 47 分钟前
nginx 可以换一个思路保护:
(1) 必须域名访问: stream 模块里加 map $ssl_preread_server_name,不要设置 default 。如果黑客不知道 SNI,nginx 会直接挂断 TCP 连接,不会进行 TLS 协商
(2) 启用双向证书(mTLS)保护: HTTPS 网站在 nginx 里启用客户端证书认证,如果没有客户端证书 nginx 就无法建立 tls 连接,保护后端业务。windows 、macos 、ios 、android 的浏览器都是原厂支持客户端证书的

实施以上 2 条后,可以不用禁止国外 ip
WizardLeo
16 小时 8 分钟前
只开放 vpn 、p2p 端口,实在要用反代也套一层 nginx 用 sni 进行端口复用。
moioooo
11 小时 59 分钟前
防火墙设置只允许特定 ip 访问(内网除外)就行,然后找个小鸡搭个代理。客户端用这个代理访问 nas 就行。
只要你的代理不泄漏,别人也访问不了 nas 了。
PerFectTime
10 小时 15 分钟前
开 ss 回家,要映射服务到公网的前置套一层 oauth 认证
benjaminliangcom
10 小时 2 分钟前
@wonderfulcxm #3 其实直接用 CLoudfalre tunnel 就行了,可以零信任,可以 mtls ,也可以 WAF
zhouu
9 小时 50 分钟前
我用 pangolin 这套方案
realdaniel
9 小时 1 分钟前
ubuntu 可以安装 knockd ,要用时开门,用完关门。
archxm
8 小时 30 分钟前
首先要有实际需求,有了数据,之后,才考虑安全。
否则你 80%时间精力,都在思考,这安不安全,如何才能安全!
likooo125802023
7 小时 33 分钟前
直接用内网回来,啥安全都不用,反正也不用公开给别人访问
AutumnVerse
7 小时 22 分钟前
我的方案:

物理机是 pve ,内部有 10 多个虚拟机。所有内网服务禁止公网入站,仅有需要的机器允许公网出站。

内网机器安装 xray ,每分钟通过 http 给外网机器发送消息。外网机器记录服务器 ip ,然后生成 clash 订阅链接。我手机、公司电脑安装 claash ,添加内网订阅,然后在任何地方都能无感进入家里内网
Ketteiron
7 小时 4 分钟前
1. 物理机安装 ubuntu
2. tailscale
完事,搞得越复杂反而越容易出错
xingheng
5 小时 51 分钟前
@archxm 直接假定“我要远程访问自己拍的毛片”

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1190501

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX