Debian 安装 Redis 完整指南 🚀

53 阅读9分钟

完整的 Redis 安装、配置、安全设置和远程访问指南


📋 目录

  1. 系统准备
  2. 安装 Redis
  3. 配置文件详解
  4. 安全配置
  5. 远程访问配置
  6. 服务管理
  7. 测试验证
  8. 常见问题

1. 系统准备

1.1 更新系统软件包列表

# 更新软件包列表
sudo apt update

# (可选)升级现有软件包
sudo apt upgrade -y

1.2 查看系统信息

# 查看 Debian 版本
cat /etc/debian_version

# 查看系统详细信息
uname -a

2. 安装 Redis

2.1 安装 Redis 服务器

# 安装 Redis 服务器和客户端工具
sudo apt install redis-server -y

2.2 查看安装版本

# 查看 Redis 版本
redis-server --version

# 或者
redis-cli --version

2.3 验证服务状态

# 查看 Redis 服务状态
sudo systemctl status redis-server

3. 配置文件详解

3.1 配置文件位置

Redis 主配置文件位置:/etc/redis/redis.conf

3.2 备份原配置文件(重要!)

# 备份原始配置文件
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup

# 添加时间戳的备份
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup.$(date +%Y%m%d_%H%M%S)

3.3 编辑配置文件

# 使用 nano 编辑器
sudo nano /etc/redis/redis.conf

# 或使用 vim
sudo vim /etc/redis/redis.conf

4. 安全配置

4.1 设置访问密码 🔐

找到并修改以下配置:

# 在配置文件中找到这一行(通常在第 1000 行左右)
# requirepass foobared

# 取消注释并修改为您的强密码
requirepass YourStrongPassword123!@#

推荐密码策略:

  • 至少 16 位字符
  • 包含大小写字母、数字和特殊字符
  • 避免使用常见单词

示例强密码:

requirepass R3d!s#Secur3P@ssw0rd2024

4.2 重命名危险命令(可选但推荐)

在配置文件中添加:

# 重命名危险命令
rename-command FLUSHDB "REDIS_FLUSHDB_MY_SECRET_NAME"
rename-command FLUSHALL "REDIS_FLUSHALL_MY_SECRET_NAME"
rename-command CONFIG "REDIS_CONFIG_MY_SECRET_NAME"
rename-command KEYS "REDIS_KEYS_MY_SECRET_NAME"

# 或者完全禁用这些命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""

5. 远程访问配置

5.1 修改绑定地址

找到 bind 配置项:

# 默认配置(仅本地访问)
bind 127.0.0.1 ::1

# 修改为以下选项之一:

# 选项1:允许所有 IP 访问(不推荐生产环境)
bind 0.0.0.0

# 选项2:允许特定 IP 访问(推荐)
bind 127.0.0.1 192.168.1.100 192.168.1.101

# 选项3:绑定到服务器的内网 IP
bind 127.0.0.1 192.168.1.10

5.2 关闭保护模式

# 找到这一行
protected-mode yes

# 修改为
protected-mode no

⚠️ 安全警告: 关闭保护模式前请务必设置密码!

5.3 修改监听端口(可选)

# 默认端口
port 6379

# 修改为自定义端口(增加安全性)
port 16379

5.4 配置最大连接数

# 设置最大客户端连接数
maxclients 10000

5.5 配置持久化

# RDB 持久化配置
save 900 1      # 900秒内至少1个key变化,就保存
save 300 10     # 300秒内至少10个key变化,就保存
save 60 10000   # 60秒内至少10000个key变化,就保存

# AOF 持久化配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec  # 每秒同步一次

5.6 配置日志

# 日志级别
loglevel notice

# 日志文件位置
logfile /var/log/redis/redis-server.log

6. 服务管理

6.1 重启 Redis 服务

# 重启服务使配置生效
sudo systemctl restart redis-server

# 或使用
sudo service redis-server restart

6.2 查看服务状态

# 查看服务状态
sudo systemctl status redis-server

# 查看服务是否在运行
ps aux | grep redis

6.3 设置开机自启

# 启用开机自启动
sudo systemctl enable redis-server

# 查看是否已启用
sudo systemctl is-enabled redis-server

6.4 停止和启动服务

# 停止服务
sudo systemctl stop redis-server

# 启动服务
sudo systemctl start redis-server

# 重载配置(不重启)
sudo systemctl reload redis-server

6.5 查看日志

# 查看实时日志
sudo tail -f /var/log/redis/redis-server.log

# 查看最近100行日志
sudo tail -n 100 /var/log/redis/redis-server.log

# 使用 journalctl 查看
sudo journalctl -u redis-server -f

7. 测试验证

7.1 本地测试连接

# 无密码连接
redis-cli

# 带密码连接
redis-cli -a YourStrongPassword123!@#

# 或先连接再认证
redis-cli
127.0.0.1:6379> AUTH YourStrongPassword123!@#
127.0.0.1:6379> PING

7.2 测试基本命令

# 连接后执行
127.0.0.1:6379> PING
PONG

# 设置键值
127.0.0.1:6379> SET testkey "Hello Redis"
OK

# 获取值
127.0.0.1:6379> GET testkey
"Hello Redis"

# 查看服务器信息
127.0.0.1:6379> INFO

# 查看配置
127.0.0.1:6379> CONFIG GET *

# 删除测试键
127.0.0.1:6379> DEL testkey

7.3 远程机器测试

在其他机器上执行:

# 基本连接
redis-cli -h 192.168.1.10 -p 6379 -a YourStrongPassword123!@#

# 连接并执行命令
redis-cli -h 192.168.1.10 -p 6379 -a YourStrongPassword123!@# PING

# 使用 telnet 测试端口连通性
telnet 192.168.1.10 6379

# 使用 nc 测试
nc -zv 192.168.1.10 6379

7.4 性能测试

# 基准测试
redis-benchmark -h 192.168.1.10 -p 6379 -a YourStrongPassword123!@# -c 50 -n 10000

# 测试特定命令
redis-benchmark -h 192.168.1.10 -a YourStrongPassword123!@# -t set,get -n 100000 -q

8. 防火墙配置

8.1 UFW 防火墙配置

# 检查 UFW 状态
sudo ufw status

# 允许 Redis 端口(所有IP)
sudo ufw allow 6379/tcp

# 允许特定 IP 访问 Redis
sudo ufw allow from 192.168.1.100 to any port 6379

# 允许特定网段访问
sudo ufw allow from 192.168.1.0/24 to any port 6379

# 启用防火墙
sudo ufw enable

# 查看规则
sudo ufw status numbered

8.2 iptables 防火墙配置

# 允许特定 IP 访问
sudo iptables -A INPUT -p tcp -s 192.168.1.100 --dport 6379 -j ACCEPT

# 允许特定网段访问
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 6379 -j ACCEPT

# 拒绝其他所有访问
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP

# 保存规则
sudo netfilter-persistent save
sudo iptables-save > /etc/iptables/rules.v4

8.3 firewalld 防火墙配置

# 添加 Redis 端口
sudo firewall-cmd --permanent --add-port=6379/tcp

# 只允许特定 IP
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port protocol="tcp" port="6379" accept'

# 重载配置
sudo firewall-cmd --reload

# 查看规则
sudo firewall-cmd --list-all

9. 常见问题解决

9.1 连接被拒绝

问题: Could not connect to Redis at 127.0.0.1:6379: Connection refused

解决方案:

# 1. 检查 Redis 是否运行
sudo systemctl status redis-server

# 2. 检查端口监听
sudo netstat -tulpn | grep 6379
# 或
sudo ss -tulpn | grep 6379

# 3. 启动 Redis
sudo systemctl start redis-server

9.2 无法远程连接

检查清单:

# 1. 检查绑定地址
grep "^bind" /etc/redis/redis.conf

# 2. 检查保护模式
grep "^protected-mode" /etc/redis/redis.conf

# 3. 检查防火墙
sudo ufw status
sudo iptables -L -n | grep 6379

# 4. 检查端口监听
sudo netstat -tulpn | grep redis

# 5. 测试网络连通性
ping 服务器IP
telnet 服务器IP 6379

9.3 认证失败

问题: (error) NOAUTH Authentication required

解决方案:

# 连接时提供密码
redis-cli -a YourPassword

# 或连接后认证
redis-cli
127.0.0.1:6379> AUTH YourPassword

9.4 内存不足

配置内存限制:

# 编辑配置文件
sudo nano /etc/redis/redis.conf

# 添加或修改
maxmemory 2gb
maxmemory-policy allkeys-lru

# 重启服务
sudo systemctl restart redis-server

9.5 查看 Redis 占用的资源

# 查看内存使用
redis-cli -a YourPassword INFO memory

# 查看统计信息
redis-cli -a YourPassword INFO stats

# 查看客户端连接
redis-cli -a YourPassword CLIENT LIST

# 系统资源占用
top -p $(pgrep redis-server)

10. 生产环境建议配置

10.1 完整配置示例

# 网络配置
bind 127.0.0.1 内网IP
protected-mode yes
port 6379
tcp-backlog 511
timeout 300
tcp-keepalive 300

# 安全配置
requirepass R3d!s#Secur3P@ssw0rd2024
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""

# 内存配置
maxmemory 4gb
maxmemory-policy allkeys-lru
maxmemory-samples 5

# 持久化配置
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis

# AOF 配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 日志配置
loglevel notice
logfile /var/log/redis/redis-server.log
syslog-enabled no

# 客户端配置
maxclients 10000

# 慢查询配置
slowlog-log-slower-than 10000
slowlog-max-len 128

10.2 系统参数优化

# 编辑系统参数
sudo nano /etc/sysctl.conf

# 添加以下内容
vm.overcommit_memory = 1
net.core.somaxconn = 511

# 使配置生效
sudo sysctl -p

# 禁用透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled

10.3 性能监控脚本

创建监控脚本:

#!/bin/bash
# redis_monitor.sh

REDIS_CLI="redis-cli -a YourPassword"

echo "=== Redis 监控信息 ==="
echo "时间: $(date)"
echo ""

echo "=== 内存使用 ==="
$REDIS_CLI INFO memory | grep "used_memory_human\|maxmemory_human"
echo ""

echo "=== 连接数 ==="
$REDIS_CLI INFO clients | grep "connected_clients"
echo ""

echo "=== 命令统计 ==="
$REDIS_CLI INFO stats | grep "instantaneous_ops_per_sec"
echo ""

echo "=== 慢查询 ==="
$REDIS_CLI SLOWLOG GET 10

11. 卸载 Redis

如果需要完全卸载 Redis:

# 停止服务
sudo systemctl stop redis-server
sudo systemctl disable redis-server

# 卸载软件包
sudo apt remove redis-server -y
sudo apt purge redis-server -y
sudo apt autoremove -y

# 删除数据和配置文件
sudo rm -rf /etc/redis
sudo rm -rf /var/lib/redis
sudo rm -rf /var/log/redis

# 删除 Redis 用户
sudo deluser redis

12. 快速命令参考

常用管理命令

# 服务管理
sudo systemctl start redis-server      # 启动
sudo systemctl stop redis-server       # 停止
sudo systemctl restart redis-server    # 重启
sudo systemctl status redis-server     # 状态
sudo systemctl enable redis-server     # 开机自启

# 配置检查
redis-server --test-memory 1024        # 测试内存
redis-cli -a password CONFIG GET *     # 查看所有配置
redis-cli -a password CONFIG GET maxmemory  # 查看特定配置

# 数据操作
redis-cli -a password SAVE            # 立即保存
redis-cli -a password BGSAVE          # 后台保存
redis-cli -a password FLUSHALL        # 清空所有数据
redis-cli -a password FLUSHDB         # 清空当前数据库

# 监控
redis-cli -a password MONITOR         # 实时监控命令
redis-cli -a password INFO            # 查看信息
redis-cli --stat                      # 实时统计
redis-cli --bigkeys -a password       # 查找大键

📝 总结

完成以上步骤后,您的 Redis 服务将:

✅ 已成功安装并运行
✅ 设置了强密码保护
✅ 配置了远程访问
✅ 配置了防火墙规则
✅ 启用了持久化
✅ 设置了开机自启动

安全提醒:

  1. ⚠️ 始终使用强密码
  2. ⚠️ 限制访问 IP 范围
  3. ⚠️ 定期备份数据
  4. ⚠️ 监控资源使用情况
  5. ⚠️ 及时更新 Redis 版本

生产环境额外建议:

  • 使用 Redis Sentinel 实现高可用
  • 配置 Redis Cluster 实现分布式
  • 使用 Redis Exporter + Prometheus 监控
  • 配置定时备份任务
  • 使用 TLS/SSL 加密连接

文档版本: v1.0
更新日期: 2024-11
适用系统: Debian 10/11/12

如有问题,请检查日志文件:/var/log/redis/redis-server.log


🎁 附赠:Python 一键安装脚本

为了简化安装流程,我们提供了一个 Python 自动化安装脚本,支持密码配置和内网远程访问。

脚本特点

功能亮点:

  • 🚀 一键自动安装 Redis
  • 🔐 支持自动生成强密码或手动输入密码
  • 🌐 自动配置内网远程访问(0.0.0.0:6379)
  • 🔥 自动配置防火墙规则
  • ⚙️ 优化生产环境配置(AOF 持久化、连接超时等)
  • 🎯 自动测试连接和验证
  • 📋 生成详细的配置摘要和使用说明
  • 💾 自动保存密码到安全文件

下载脚本

将以下内容保存为 install_redis.py

# 方法1:直接下载(如果您已上传到服务器)
wget https://your-server.com/install_redis.py

# 方法2:从项目仓库获取
# 请参考本指南同目录下的 install_redis.py 文件

# 方法3:手动创建
nano install_redis.py
# 然后复制脚本内容(见下文或项目文件)

使用方法

基本使用

# 1. 赋予执行权限
chmod +x install_redis.py

# 2. 运行脚本(需要 root 权限)
sudo python3 install_redis.py

安装流程

  1. 密码设置

    • 选项 1:自动生成 20 位强密码(推荐)
    • 选项 2:手动输入密码(最少 12 位)
  2. 自动安装

    • 更新系统软件包
    • 安装 Redis 服务器
    • 配置远程访问和密码
    • 启用 AOF 持久化
    • 配置防火墙规则
    • 设置开机自启动
  3. 测试验证

    • 测试本地连接
    • 测试基本操作(SET/GET)
    • 验证端口监听
  4. 完成安装

    • 显示详细配置信息
    • 提供连接示例
    • 保存密码到 /root/redis_password.txt

脚本输出示例

======================================================================
  🎉 Redis 安装配置完成!
======================================================================

📋 安装信息:
  • Redis 版本: Redis server v=7.0.12
  • 配置文件: /etc/redis/redis.conf
  • 数据目录: /var/lib/redis
  • 日志文件: /var/log/redis/redis-server.log

🔐 认证信息:
  • 密码: Xy9@kL2#mN8pQ4!rT6vZ
  ⚠️  请务必保存此密码!

🌐 连接信息:
  • 服务器 IP: 192.168.1.100Redis 地址: 192.168.1.100:6379
  • 本地连接: 127.0.0.1:6379

🛠 服务管理:
  systemctl start redis-server      # 启动
  systemctl stop redis-server       # 停止
  systemctl restart redis-server    # 重启
  systemctl status redis-server     # 状态
  journalctl -u redis-server -f     # 日志

📝 常用命令:
  # 连接 Redis
  redis-cli -a 'Xy9@kL2#mN8pQ4!rT6vZ'

  # 远程连接
  redis-cli -h 192.168.1.100 -p 6379 -a 'Xy9@kL2#mN8pQ4!rT6vZ'

脚本功能详解

1. 自动密码管理

自动生成强密码:

  • 长度:20 位
  • 字符集:大小写字母 + 数字 + 特殊符号
  • 使用 secrets 模块确保密码强度

手动输入密码:

  • 最少 12 位
  • 二次确认防止输入错误
  • 实时验证密码强度

2. 远程访问配置

脚本会自动配置以下选项:

# 监听所有接口
bind 0.0.0.0 ::0

# 关闭保护模式(已设置密码)
protected-mode no

# 设置访问密码
requirepass YourPassword

3. 性能优化配置

# 启用 AOF 持久化
appendonly yes

# 内存管理策略
maxmemory-policy allkeys-lru

# TCP 连接保活
timeout 300
tcp-keepalive 300

# 日志级别
loglevel notice

4. 防火墙自动配置

脚本会自动检测并配置 UFW 防火墙:

# 允许 Redis 端口
ufw allow 6379/tcp

客户端连接示例

Python 连接

import redis

# 创建连接
r = redis.Redis(
    host='192.168.1.100',
    port=6379,
    password='Xy9@kL2#mN8pQ4!rT6vZ',
    decode_responses=True
)

# 测试连接
print(r.ping())  # 输出: True

# 基本操作
r.set('name', 'Redis')
print(r.get('name'))  # 输出: Redis

Java 连接(Jedis)

import redis.clients.jedis.Jedis;

public class RedisExample {
    public static void main(String[] args) {
        // 创建连接
        Jedis jedis = new Jedis("192.168.1.100", 6379);
        
        // 认证
        jedis.auth("Xy9@kL2#mN8pQ4!rT6vZ");
        
        // 测试连接
        System.out.println(jedis.ping());  // 输出: PONG
        
        // 基本操作
        jedis.set("name", "Redis");
        System.out.println(jedis.get("name"));  // 输出: Redis
        
        jedis.close();
    }
}

Node.js 连接

const redis = require('redis');

// 创建连接
const client = redis.createClient({
    host: '192.168.1.100',
    port: 6379,
    password: 'Xy9@kL2#mN8pQ4!rT6vZ'
});

// 连接
client.connect();

// 基本操作
await client.set('name', 'Redis');
const value = await client.get('name');
console.log(value);  // 输出: Redis

PHP 连接

<?php
$redis = new Redis();

// 连接
$redis->connect('192.168.1.100', 6379);

// 认证
$redis->auth('Xy9@kL2#mN8pQ4!rT6vZ');

// 测试连接
echo $redis->ping();  // 输出: +PONG

// 基本操作
$redis->set('name', 'Redis');
echo $redis->get('name');  // 输出: Redis
?>

安全增强建议

1. 限制访问 IP(推荐)

编辑配置文件:

sudo nano /etc/redis/redis.conf

# 只允许特定 IP 访问
bind 127.0.0.1 192.168.1.100 192.168.1.101

# 重启服务
sudo systemctl restart redis-server

或使用防火墙:

# 删除全局规则
sudo ufw delete allow 6379/tcp

# 只允许特定网段
sudo ufw allow from 192.168.1.0/24 to any port 6379

# 或只允许特定 IP
sudo ufw allow from 192.168.1.100 to any port 6379
sudo ufw allow from 192.168.1.101 to any port 6379

2. 修改默认端口

# 编辑配置
sudo nano /etc/redis/redis.conf

# 修改端口
port 16379

# 更新防火墙
sudo ufw allow 16379/tcp
sudo ufw delete allow 6379/tcp

# 重启服务
sudo systemctl restart redis-server

3. 禁用危险命令

# 编辑配置文件
sudo nano /etc/redis/redis.conf

# 添加以下内容
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""
rename-command SHUTDOWN ""

# 重启服务
sudo systemctl restart redis-server

4. 启用 TLS/SSL(高级)

# 生成证书
cd /etc/redis
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout redis.key -out redis.crt

# 编辑配置
sudo nano /etc/redis/redis.conf

# 添加 TLS 配置
port 0
tls-port 6379
tls-cert-file /etc/redis/redis.crt
tls-key-file /etc/redis/redis.key
tls-ca-cert-file /etc/redis/ca.crt

# 重启服务
sudo systemctl restart redis-server

密码管理

脚本会自动将密码保存到 /root/redis_password.txt

# 查看保存的密码
sudo cat /root/redis_password.txt

# 输出示例:
# Redis Password: Xy9@kL2#mN8pQ4!rT6vZ
# Server: 192.168.1.100:6379
# Installation Date: 2024-11-06 10:30:45

故障排查

脚本运行失败

# 查看详细错误
sudo python3 install_redis.py

# 检查 Python 版本
python3 --version  # 需要 Python 3.6+

# 安装必要依赖
sudo apt update
sudo apt install -y python3 python3-pip

远程连接失败

# 1. 检查 Redis 是否运行
sudo systemctl status redis-server

# 2. 检查端口监听
sudo netstat -tulpn | grep 6379
# 应该显示: 0.0.0.0:6379

# 3. 检查防火墙
sudo ufw status
sudo ufw allow 6379/tcp

# 4. 测试本地连接
redis-cli -a 'YourPassword' PING

# 5. 检查配置
grep "^bind" /etc/redis/redis.conf
grep "^protected-mode" /etc/redis/redis.conf

密码认证失败

# 查看配置中的密码
sudo grep "^requirepass" /etc/redis/redis.conf

# 测试密码
redis-cli -a 'YourPassword' PING

# 查看保存的密码
sudo cat /root/redis_password.txt

卸载

如需卸载 Redis:

# 停止服务
sudo systemctl stop redis-server
sudo systemctl disable redis-server

# 卸载软件包
sudo apt remove --purge redis-server -y
sudo apt autoremove -y

# 删除数据和配置
sudo rm -rf /etc/redis
sudo rm -rf /var/lib/redis
sudo rm -rf /var/log/redis

# 删除密码文件
sudo rm -f /root/redis_password.txt

# 删除防火墙规则
sudo ufw delete allow 6379/tcp

脚本源码

将以下完整代码保存为 install_redis.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Redis 一键安装配置脚本
支持密码设置和内网远程访问

使用方法:
    sudo python3 install_redis.py
    
功能:
    - 自动安装 Redis
    - 配置强密码保护
    - 支持内网远程访问
    - 配置防火墙规则
    - 设置开机自启动
    - 优化生产环境配置
"""

import os
import sys
import subprocess
import time
import re
import shutil
import getpass
import secrets
import string

# 颜色输出
class Colors:
    GREEN = '\033[0;32m'
    YELLOW = '\033[1;33m'
    RED = '\033[0;31m'
    BLUE = '\033[0;34m'
    CYAN = '\033[0;36m'
    NC = '\033[0m'
    BOLD = '\033[1m'

def print_step(message):
    """打印步骤信息"""
    print(f"\n{Colors.CYAN}{'='*70}{Colors.NC}")
    print(f"{Colors.GREEN}{Colors.BOLD}{message}{Colors.NC}")
    print(f"{Colors.CYAN}{'='*70}{Colors.NC}\n")

def print_success(message):
    """打印成功信息"""
    print(f"{Colors.GREEN}{message}{Colors.NC}")

def print_error(message):
    """打印错误信息"""
    print(f"{Colors.RED}{message}{Colors.NC}")

def print_warning(message):
    """打印警告信息"""
    print(f"{Colors.YELLOW}{message}{Colors.NC}")

def print_info(message):
    """打印信息"""
    print(f"{Colors.BLUE}{message}{Colors.NC}")

def run_command(command, show_output=True, check=True):
    """执行系统命令"""
    try:
        if show_output:
            result = subprocess.run(command, shell=True, check=check,
                                  stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                  text=True, encoding='utf-8')
            if result.stdout and result.stdout.strip():
                print(result.stdout)
            if result.stderr and result.returncode != 0:
                print_error(result.stderr)
            return result.returncode == 0
        else:
            result = subprocess.run(command, shell=True, check=check,
                                  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            return result.returncode == 0
    except subprocess.CalledProcessError as e:
        print_error(f"命令执行失败: {command}")
        return False

def check_root():
    """检查是否为 root 用户"""
    if os.geteuid() != 0:
        print_error("此脚本需要 root 权限运行!")
        print_info("请使用: sudo python3 install_redis.py")
        sys.exit(1)

def get_server_ip():
    """获取服务器 IP 地址"""
    result = subprocess.run("hostname -I | awk '{print $1}'", shell=True,
                          capture_output=True, text=True)
    return result.stdout.strip() if result.returncode == 0 else "0.0.0.0"

def generate_password(length=20):
    """生成强密码"""
    characters = string.ascii_letters + string.digits + "!@#$%^&*"
    password = ''.join(secrets.choice(characters) for _ in range(length))
    return password

def get_password():
    """获取或生成 Redis 密码"""
    print_step("配置 Redis 密码")
    
    print_info("请选择密码设置方式:")
    print("  1. 自动生成强密码(推荐)")
    print("  2. 手动输入密码")
    
    choice = input(f"\n{Colors.YELLOW}请选择 (1/2) [默认: 1]: {Colors.NC}").strip()
    
    if choice == '2':
        while True:
            password1 = getpass.getpass(f"{Colors.YELLOW}请输入 Redis 密码: {Colors.NC}")
            if len(password1) < 12:
                print_error("密码长度至少 12 位!")
                continue
            
            password2 = getpass.getpass(f"{Colors.YELLOW}请再次输入密码: {Colors.NC}")
            if password1 != password2:
                print_error("两次密码不一致,请重新输入!")
                continue
            
            print_success("密码设置成功")
            return password1
    else:
        password = generate_password(20)
        print_success("已生成强密码")
        print_warning(f"请务必保存以下密码:\n")
        print(f"{Colors.CYAN}{Colors.BOLD}  {password}{Colors.NC}\n")
        
        input(f"{Colors.YELLOW}请确认已保存密码,按 Enter 继续...{Colors.NC}")
        return password

def check_redis_installed():
    """检查 Redis 是否已安装"""
    result = subprocess.run("redis-server --version", shell=True,
                          stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    return result.returncode == 0

def install_redis():
    """安装 Redis"""
    print_step("步骤 1: 安装 Redis")
    
    if check_redis_installed():
        print_info("Redis 已安装")
        result = subprocess.run("redis-server --version", shell=True,
                              capture_output=True, text=True)
        print_info(result.stdout.strip())
        
        response = input(f"\n{Colors.YELLOW}是否重新安装? (y/N): {Colors.NC}").strip().lower()
        if response != 'y':
            return True
    
    print_info("正在更新软件包列表...")
    if not run_command("apt update", show_output=False):
        print_error("更新软件包列表失败")
        return False
    
    print_info("正在安装 Redis...")
    if not run_command("apt install -y redis-server", show_output=True):
        print_error("Redis 安装失败")
        return False
    
    # 验证安装
    result = subprocess.run("redis-server --version", shell=True,
                          capture_output=True, text=True)
    if result.returncode == 0:
        print_success("Redis 安装成功")
        print_info(result.stdout.strip())
        return True
    else:
        print_error("Redis 安装验证失败")
        return False

def backup_config():
    """备份配置文件"""
    config_file = "/etc/redis/redis.conf"
    if not os.path.exists(config_file):
        print_error(f"配置文件不存在: {config_file}")
        return False
    
    backup_file = f"{config_file}.backup.{int(time.time())}"
    shutil.copy(config_file, backup_file)
    print_success(f"配置文件已备份: {backup_file}")
    return True

def configure_redis(password, server_ip):
    """配置 Redis"""
    print_step("步骤 2: 配置 Redis")
    
    config_file = "/etc/redis/redis.conf"
    
    # 备份配置
    if not backup_config():
        return False
    
    # 读取配置文件
    with open(config_file, 'r') as f:
        config_content = f.read()
    
    print_info("配置远程访问...")
    
    # 修改 bind - 允许所有 IP 访问(生产环境建议限制具体 IP)
    config_content = re.sub(
        r'^bind\s+.*$',
        f'bind 0.0.0.0 ::0',
        config_content,
        flags=re.MULTILINE
    )
    
    # 关闭保护模式(已设置密码,可以安全关闭)
    config_content = re.sub(
        r'^protected-mode\s+.*$',
        'protected-mode no',
        config_content,
        flags=re.MULTILINE
    )
    
    print_info("配置密码保护...")
    
    # 设置密码
    # 先尝试替换已存在的 requirepass(包括注释的)
    if re.search(r'#?\s*requirepass', config_content):
        config_content = re.sub(
            r'#?\s*requirepass\s+.*$',
            f'requirepass {password}',
            config_content,
            flags=re.MULTILINE
        )
    else:
        # 如果没有 requirepass 配置,添加到文件末尾
        config_content += f"\n# Password protection\nrequirepass {password}\n"
    
    print_info("配置性能优化...")
    
    # 配置持久化
    config_content = re.sub(
        r'^appendonly\s+.*$',
        'appendonly yes',
        config_content,
        flags=re.MULTILINE
    )
    
    if not re.search(r'^appendonly\s+', config_content, re.MULTILINE):
        config_content += "\n# AOF persistence\nappendonly yes\n"
    
    # 配置日志级别
    config_content = re.sub(
        r'^loglevel\s+.*$',
        'loglevel notice',
        config_content,
        flags=re.MULTILINE
    )
    
    # 配置最大内存策略(可选,根据需要调整)
    if not re.search(r'^maxmemory-policy', config_content, re.MULTILINE):
        config_content += "\n# Memory management\nmaxmemory-policy allkeys-lru\n"
    
    # 配置TCP参数
    modifications = {
        r'^timeout\s+.*$': 'timeout 300',
        r'^tcp-keepalive\s+.*$': 'tcp-keepalive 300',
    }
    
    for pattern, replacement in modifications.items():
        if re.search(pattern, config_content, re.MULTILINE):
            config_content = re.sub(pattern, replacement, config_content, flags=re.MULTILINE)
    
    # 写入配置文件
    with open(config_file, 'w') as f:
        f.write(config_content)
    
    print_success("Redis 配置完成")
    print_info(f"  • 监听地址: 0.0.0.0:6379")
    print_info(f"  • 外部访问: {server_ip}:6379")
    print_info(f"  • 密码保护: 已启用")
    print_info(f"  • AOF 持久化: 已启用")
    
    return True

def configure_systemd():
    """配置 systemd 服务"""
    print_step("步骤 3: 配置 systemd 服务")
    
    # Redis 在 Debian 上默认使用 systemd,只需确保配置正确
    # 修改 systemd 服务文件以使用 supervised systemd
    config_file = "/etc/redis/redis.conf"
    
    with open(config_file, 'r') as f:
        config_content = f.read()
    
    # 配置 supervised systemd
    if re.search(r'^supervised\s+', config_content, re.MULTILINE):
        config_content = re.sub(
            r'^supervised\s+.*$',
            'supervised systemd',
            config_content,
            flags=re.MULTILINE
        )
    else:
        config_content += "\n# Systemd supervision\nsupervised systemd\n"
    
    with open(config_file, 'w') as f:
        f.write(config_content)
    
    print_success("systemd 配置完成")
    return True

def restart_redis():
    """重启 Redis 服务"""
    print_step("步骤 4: 启动 Redis 服务")
    
    print_info("正在重启 Redis 服务...")
    if not run_command("systemctl restart redis-server", show_output=False):
        print_error("Redis 重启失败")
        print_info("查看日志:")
        run_command("journalctl -u redis-server -n 50 --no-pager")
        return False
    
    print_success("Redis 服务已重启")
    
    # 等待服务完全启动
    print_info("等待服务启动...")
    time.sleep(3)
    
    # 检查服务状态
    result = subprocess.run("systemctl is-active redis-server", shell=True,
                          capture_output=True, text=True)
    if result.stdout.strip() == "active":
        print_success("Redis 服务运行正常")
    else:
        print_error("Redis 服务未正常运行")
        return False
    
    # 设置开机自启动
    run_command("systemctl enable redis-server", show_output=False)
    print_success("已设置开机自启动")
    
    return True

def configure_firewall():
    """配置防火墙"""
    print_step("步骤 5: 配置防火墙")
    
    result = subprocess.run("which ufw", shell=True,
                          stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    
    if result.returncode == 0:
        print_info("检测到 UFW 防火墙")
        
        result = subprocess.run("ufw status", shell=True,
                              capture_output=True, text=True)
        
        if "inactive" not in result.stdout.lower():
            print_info("添加防火墙规则...")
            
            # 允许 Redis 端口
            run_command("ufw allow 6379/tcp", show_output=False)
            print_success("已添加防火墙规则:允许 6379/tcp")
            
            print_warning("建议生产环境限制访问 IP,例如:")
            print(f"  {Colors.CYAN}sudo ufw delete allow 6379/tcp{Colors.NC}")
            print(f"  {Colors.CYAN}sudo ufw allow from 192.168.1.0/24 to any port 6379{Colors.NC}")
        else:
            print_warning("UFW 防火墙未启用,跳过配置")
    else:
        print_warning("未检测到 UFW 防火墙")
    
    return True

def test_redis(password):
    """测试 Redis 连接"""
    print_step("步骤 6: 测试 Redis 连接")
    
    # 测试本地连接
    print_info("测试本地连接...")
    result = subprocess.run(
        f'redis-cli -a "{password}" PING 2>/dev/null',
        shell=True,
        capture_output=True,
        text=True
    )
    
    if "PONG" in result.stdout:
        print_success("✓ 本地连接成功")
    else:
        print_error("✗ 本地连接失败")
        return False
    
    # 测试设置和获取
    print_info("测试基本操作...")
    
    # SET 测试
    result = subprocess.run(
        f'redis-cli -a "{password}" SET test_key "Hello Redis" 2>/dev/null',
        shell=True,
        capture_output=True,
        text=True
    )
    
    if "OK" in result.stdout:
        print_success("✓ SET 操作成功")
    else:
        print_warning("⚠ SET 操作失败")
    
    # GET 测试
    result = subprocess.run(
        f'redis-cli -a "{password}" GET test_key 2>/dev/null',
        shell=True,
        capture_output=True,
        text=True
    )
    
    if "Hello Redis" in result.stdout:
        print_success("✓ GET 操作成功")
    else:
        print_warning("⚠ GET 操作失败")
    
    # 清理测试数据
    subprocess.run(
        f'redis-cli -a "{password}" DEL test_key 2>/dev/null',
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )
    
    # 检查端口监听
    print_info("检查端口监听...")
    result = subprocess.run(
        "netstat -tulpn 2>/dev/null | grep 6379 || ss -tulpn 2>/dev/null | grep 6379",
        shell=True,
        capture_output=True,
        text=True
    )
    
    if "6379" in result.stdout:
        if "0.0.0.0:6379" in result.stdout or ":::6379" in result.stdout:
            print_success("✓ Redis 正在监听所有接口 (0.0.0.0:6379)")
        else:
            print_warning("⚠ Redis 仅监听本地接口")
    else:
        print_error("✗ 未检测到 Redis 端口监听")
    
    return True

def print_summary(password, server_ip):
    """打印安装摘要"""
    print(f"\n{Colors.GREEN}{'='*70}{Colors.NC}")
    print(f"{Colors.GREEN}{Colors.BOLD}{'  🎉 Redis 安装配置完成!':^70}{Colors.NC}")
    print(f"{Colors.GREEN}{'='*70}{Colors.NC}\n")
    
    # 获取 Redis 版本
    result = subprocess.run("redis-server --version", shell=True,
                          capture_output=True, text=True)
    version = result.stdout.strip() if result.returncode == 0 else "未知"
    
    print(f"{Colors.BOLD}📋 安装信息:{Colors.NC}")
    print(f"  • Redis 版本: {Colors.YELLOW}{version}{Colors.NC}")
    print(f"  • 配置文件: /etc/redis/redis.conf")
    print(f"  • 数据目录: /var/lib/redis")
    print(f"  • 日志文件: /var/log/redis/redis-server.log")
    
    print(f"\n{Colors.BOLD}🔐 认证信息:{Colors.NC}")
    print(f"  • 密码: {Colors.CYAN}{Colors.BOLD}{password}{Colors.NC}")
    print(f"  {Colors.RED}⚠️  请务必保存此密码!{Colors.NC}")
    
    print(f"\n{Colors.BOLD}🌐 连接信息:{Colors.NC}")
    print(f"  • 服务器 IP: {Colors.YELLOW}{server_ip}{Colors.NC}")
    print(f"  • Redis 地址: {Colors.CYAN}{server_ip}:6379{Colors.NC}")
    print(f"  • 本地连接: {Colors.CYAN}127.0.0.1:6379{Colors.NC}")
    
    print(f"\n{Colors.BOLD}🛠 服务管理:{Colors.NC}")
    print(f"  {Colors.CYAN}systemctl start redis-server{Colors.NC}      # 启动")
    print(f"  {Colors.CYAN}systemctl stop redis-server{Colors.NC}       # 停止")
    print(f"  {Colors.CYAN}systemctl restart redis-server{Colors.NC}    # 重启")
    print(f"  {Colors.CYAN}systemctl status redis-server{Colors.NC}     # 状态")
    print(f"  {Colors.CYAN}journalctl -u redis-server -f{Colors.NC}     # 日志")
    
    print(f"\n{Colors.BOLD}📝 常用命令:{Colors.NC}")
    print(f"  # 连接 Redis")
    print(f"  {Colors.CYAN}redis-cli -a '{password}'{Colors.NC}")
    print(f"\n  # 远程连接")
    print(f"  {Colors.CYAN}redis-cli -h {server_ip} -p 6379 -a '{password}'{Colors.NC}")
    print(f"\n  # 执行命令")
    print(f"  {Colors.CYAN}redis-cli -a '{password}' PING{Colors.NC}")
    print(f"  {Colors.CYAN}redis-cli -a '{password}' INFO{Colors.NC}")
    print(f"  {Colors.CYAN}redis-cli -a '{password}' CONFIG GET *{Colors.NC}")
    
    print(f"\n{Colors.BOLD}🔗 客户端配置:{Colors.NC}")
    print(f"  Host: {Colors.CYAN}{server_ip}{Colors.NC}")
    print(f"  Port: {Colors.CYAN}6379{Colors.NC}")
    print(f"  Password: {Colors.CYAN}{password}{Colors.NC}")
    
    print(f"\n{Colors.BOLD}🐍 Python 连接示例:{Colors.NC}")
    print(f"""  {Colors.CYAN}import redis
  
  r = redis.Redis(
      host='{server_ip}',
      port=6379,
      password='{password}',
      decode_responses=True
  )
  
  r.set('key', 'value')
  print(r.get('key')){Colors.NC}""")
    
    print(f"\n{Colors.BOLD}☕ Java 连接示例:{Colors.NC}")
    print(f"""  {Colors.CYAN}Jedis jedis = new Jedis("{server_ip}", 6379);
  jedis.auth("{password}");
  jedis.set("key", "value");
  System.out.println(jedis.get("key"));{Colors.NC}""")
    
    print(f"\n{Colors.BOLD}🔧 性能测试:{Colors.NC}")
    print(f"  {Colors.CYAN}redis-benchmark -h {server_ip} -p 6379 -a '{password}' -c 50 -n 10000{Colors.NC}")
    
    print(f"\n{Colors.BOLD}⚠️  安全提醒:{Colors.NC}")
    print(f"  • ✓ 已设置强密码保护")
    print(f"  • ✓ 已配置远程访问 (0.0.0.0:6379)")
    print(f"  • ⚠ 建议使用防火墙限制访问 IP")
    print(f"  • ⚠ 生产环境建议修改默认端口")
    print(f"  • ⚠ 定期备份 Redis 数据")
    print(f"  • ⚠ 监控内存使用情况")
    
    print(f"\n{Colors.BOLD}📚 进阶配置:{Colors.NC}")
    print(f"  • 修改配置: {Colors.CYAN}sudo nano /etc/redis/redis.conf{Colors.NC}")
    print(f"  • 查看日志: {Colors.CYAN}sudo tail -f /var/log/redis/redis-server.log{Colors.NC}")
    print(f"  • 监控命令: {Colors.CYAN}redis-cli -a '{password}' MONITOR{Colors.NC}")
    print(f"  • 统计信息: {Colors.CYAN}redis-cli -a '{password}' --stat{Colors.NC}")
    
    print(f"\n{Colors.BOLD}🔒 限制特定 IP 访问(可选):{Colors.NC}")
    print(f"  {Colors.CYAN}# 编辑配置文件{Colors.NC}")
    print(f"  {Colors.CYAN}sudo nano /etc/redis/redis.conf{Colors.NC}")
    print(f"  {Colors.CYAN}# 修改 bind 行为:{Colors.NC}")
    print(f"  {Colors.CYAN}bind 127.0.0.1 192.168.1.100 192.168.1.101{Colors.NC}")
    print(f"  {Colors.CYAN}# 或使用防火墙限制{Colors.NC}")
    print(f"  {Colors.CYAN}sudo ufw delete allow 6379/tcp{Colors.NC}")
    print(f"  {Colors.CYAN}sudo ufw allow from 192.168.1.0/24 to any port 6379{Colors.NC}")
    
    print(f"\n{Colors.GREEN}{'='*70}{Colors.NC}\n")
    
    # 保存密码到文件
    password_file = "/root/redis_password.txt"
    try:
        with open(password_file, 'w') as f:
            f.write(f"Redis Password: {password}\n")
            f.write(f"Server: {server_ip}:6379\n")
            f.write(f"Installation Date: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
        os.chmod(password_file, 0o600)
        print_success(f"密码已保存到: {password_file} (仅 root 可读)")
    except Exception as e:
        print_warning(f"无法保存密码到文件: {e}")

def main():
    """主函数"""
    check_root()
    
    server_ip = get_server_ip()
    
    print(f"\n{Colors.BLUE}{'='*70}{Colors.NC}")
    print(f"{Colors.BOLD}{Colors.BLUE}{'  Redis 一键安装配置脚本':^70}{Colors.NC}")
    print(f"{Colors.BLUE}{'='*70}{Colors.NC}\n")
    
    print_info(f"服务器 IP: {server_ip}")
    print_info("此脚本将自动完成以下操作:")
    print("  1. 安装 Redis 服务器")
    print("  2. 配置强密码保护")
    print("  3. 允许内网远程访问")
    print("  4. 配置防火墙规则")
    print("  5. 设置开机自启动")
    print("  6. 优化生产环境配置")
    
    print()
    response = input(f"{Colors.YELLOW}是否继续? (Y/n): {Colors.NC}").strip().lower()
    if response == 'n':
        print_info("安装已取消")
        sys.exit(0)
    
    try:
        # 获取密码
        password = get_password()
        
        # 安装 Redis
        if not install_redis():
            sys.exit(1)
        
        # 配置 Redis
        if not configure_redis(password, server_ip):
            sys.exit(1)
        
        # 配置 systemd
        if not configure_systemd():
            sys.exit(1)
        
        # 重启服务
        if not restart_redis():
            sys.exit(1)
        
        # 配置防火墙
        configure_firewall()
        
        # 测试连接
        if not test_redis(password):
            print_warning("测试未完全通过,但服务已启动")
        
        # 打印摘要
        print_summary(password, server_ip)
        
    except KeyboardInterrupt:
        print_error("\n\n安装已被用户中断!")
        sys.exit(1)
    except Exception as e:
        print_error(f"\n发生错误: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)

if __name__ == "__main__":
    main()

脚本特点:

  • 📝 完整的错误处理
  • 🎨 彩色输出,界面友好
  • 🔧 自动备份配置文件
  • ✅ 全面的安装验证
  • 📚 详细的使用说明
  • 🔐 支持自动生成或手动输入密码
  • 🌐 自动配置远程访问
  • 💾 自动保存密码到安全文件

使用方式:

  1. 复制上面的代码并保存为 install_redis.py
  2. 赋予执行权限:chmod +x install_redis.py
  3. 运行脚本:sudo python3 install_redis.py
  4. 按照提示选择密码方式并完成安装

🎯 总结

通过本指南,您可以选择:

  1. 手动安装:适合学习和理解每个配置步骤
  2. 脚本安装:快速部署,自动化配置,节省时间

推荐做法:

  • 🔰 新手学习:建议先手动安装一次,理解原理
  • 🚀 批量部署:使用 Python 脚本,提高效率
  • 🏢 生产环境:使用脚本 + 额外安全配置

祝您使用愉快! 🎉

如有问题或建议,欢迎反馈!