云服务器部署实战:从SSH登录到Nginx反向代理全流程指南 📅 发布时间:2026/9/20 19:55:11 👁 浏览次数: 我这两天刚在一台芯飞云服务器上把一个内部工具从零部署到能对外访问整个过程走完一遍之后想把这个流程完整梳理出来。很多人一提到“服务器上跑程序”就发怵觉得要懂一堆底层原理其实日常开发部署真没那么玄乎。这篇文章就按我实际操作的顺序来写从拿到服务器IP、SSH登录开始到装环境、拉代码、跑进程、配域名、上线访问每一步都讲清楚为什么这么做以及我在这个过程中踩过的坑。不管你是个人开发者、小型团队还是第一次接触云服务器的学生都能照着把它跑通。1. 接机第一步从控制台到SSH登录1.1 初始化系统先定版本和配置拿到芯飞云服务器之后第一件事是在控制台里完成初始化。大多数云厂商的后台流程都差不多选地域、选镜像、设密码或者密钥、定带宽。这里我想多说一句配置选型因为很多人第一步就栽在这里。我的建议是除非项目只有一个静态页面否则不要用最小的1核1G。系统一启动光Linux内核加基础服务就要吃掉快一个G的内存你再装个MySQL或者Nginx内存直接见底。我用的这台是2核4G跑一个Spring Boot后端加一个Vue前端外加一个MySQL和Redis负载基本稳在50%以下。如果是个人博客或轻量API2核2G勉强够但Swap一定要配好不然高峰期容易OOM。系统镜像我选了Debian 12没选CentOS。一个重要原因是Debian系的软件包更新勤快很多新兴工具默认支持好比如Nginx官方源、NodeSource源都能很干净地装上。另一个原因是CentOS 7已经在2024年停止维护继续用就等于裸奔。如果你实在习惯RedHat系那可以选Rocky Linux或AlmaLinux但需要自己花时间适应dnf和firewalld的用法。连接方式上我推荐用密钥登录而不是密码。创建密钥对之后私钥留在本地公钥放进服务器的authorized_keys里这样就算密码泄露别人也进不来。控制台一般支持直接创建密钥对或者用本地命令生成再粘贴公钥。我第一次部署时图省事直接用密码结果看日志发现每天都有几百次来自公网的SSH爆破尝试换掉密码再上密钥之后这类骚扰基本为零。1.2 SSH连接实操终端和VSCode两条路拿到公网IP之后第一件事是确认能登录。我习惯先在本地终端里敲一条命令验证连通性ssh -i ~/.ssh/id_ed25519 root你的公网IP如果你用的是密码登录直接ssh rootIP然后输密码就行。第一次连接会提示确认主机指纹输入yes再回车。这个指纹建议记一下之后如果服务器重装或IP被复用指纹变了能马上发现。很多人到这一步会卡在“连接超时”。我遇到的情况九成是安全组没放行22端口。芯飞云控制台的防火墙规则和系统防火墙是两层公网能不能访问首先看安全组。你要在控制台里把22端口加入放行规则同时源地址最好限定成你自己的IP这样既不影响使用又减少被扫的风险。连上之后我强烈建议先跑这几个命令看一眼机器状态whoami cat /etc/os-release free -h df -h uptime这五条能让你确认系统版本、内存、磁盘和负载情况。特别是df -h服务器磁盘满导致服务挂掉是最常见的运维事故一开始就记住家底很重要。日常开发我推荐用VSCode连远程服务器。装一个Remote - SSH插件然后在左侧连接列表里填上别名和连接命令保存之后就能像编辑本地文件一样改服务器代码。这个方式对前后端开发都友好尤其是不想把生产环境代码大段复制来复制去的人。调试Python或Node时还能直接附加到远程进程效率高很多。1.3 基础安全加固别让服务器裸奔登录成功之后别急着装软件先把基础安全做了。这部分最多花十分钟但能避免之后百分之八九十的麻烦。第一步是修改SSH配置。编辑/etc/ssh/sshd_config把PermitRootLogin改成prohibit-password意思是禁止root用密码登录但允许密钥登录。再改一下Port换成1024到65535之间的一个端口这样能躲掉绝大多数自动扫描脚本。改完之后用systemctl restart sshd重启服务注意先别关当前会话等新连接测通了再关闭不然手滑就把自己锁外面了。第二步是配置防火墙。Debian系统默认没装ufw装上之后规则很直观apt update apt install -y ufw ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw enable这里只放行了SSH、HTTP和HTTPS三个端口数据库端口3306、Redis端口6379都不应该对外暴露。如果同机器上要访问走内网IP或者本地socket就行。有人为了省事把MySQL端口开公网结果密码被扫出来被勒索的案例太多了。顺带一提服务器上最好装一个fail2ban它会自动把连续登录失败的IP拉黑一段时间。我配置好之后爆破日志肉眼可见地安静了。默认配置其实就够用不用细调装上就是一种保障。2. 系统基础环境把干活的工具都备齐2.1 换源与基础软件安装Debian默认源在国外国内服务器直连会很慢。拿到机器的三分钟里先把源换成国内镜像源这一步能让后续所有的apt安装速度快好几倍。操作方法是编辑/etc/apt/sources.list把deb.debian.org整体替换成mirrors.tuna.tsinghua.edu.cn或者mirrors.aliyun.com然后apt update。这一步看着小实际体感差异巨大。我第一次没换源装个Nginx都卡在小半分钟换完之后基本秒下。接下来装一组我每次部署都会用到的基础软件包apt install -y curl wget git vim unzip tar build-essentialcurl和wget是命令行下载的标配git用来拉代码vim是在服务器上快速改配置文件的救命稻草build-essential是一套编译工具链后面装某些需要编译的Python包或Node原生模块时缺不了。这里说下vim的看法很多人一提vim就头疼其实在服务器上只需要会打开、插入、保存退出就够了。i进入编辑Esc退回命令模式:wq保存退出。三分钟就能学会但收益极高因为服务器上没有图形界面所有配置文件改动都得靠它。2.2 时间同步与系统更新服务器时间不准是个特别隐蔽的问题。明明代码里写了日志时间戳排查问题的时候发现日志时间差八个小时或者跟数据库写入时间对不上都是这个原因。Debian 12默认带systemd-timesyncd确认一下服务状态就行timedatectl status timedatectl set-timezone Asia/Shanghai timedatectl set-ntp truentp开启后系统会自动从时间服务器同步时间不用担心时区问题。这里提到的“时间服务器”是标准的NTP服务千万别为了省事手动NTP去什么奇怪来源用系统默认的就行。系统更新这块我的建议是apt upgrade每周做一次。Debian的稳定源更新很保守不会出现升级把环境搞坏的情况。倒是跳过大版本升级比如Debian 11升12这类大迁移不要在生产环境上贸然操作宁可重新初始化一台新机器再迁数据。2.3 磁盘划分与Swap分配云服务器的数据盘和系统盘经常是分开的。系统盘默认挂载在/如果买了数据盘一般需要自己格式化并挂载。用lsblk看一下磁盘列表把/dev/sdb之类的空盘格式化之后挂载到/data目录比较大的数据文件、数据库数据目录、日志文件都可以放这里。好处是未来系统盘出故障要重装数据盘可以保留不会全丢。顺便聊聊Swap。内存不够时Swap能顶一会但别把它当内存用因为几十倍的读写速度差会让程序性能雪崩。我的经验是4G内存以下配2G Swap4G以上可以不要或者配2G兜底。创建Swap的方法fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo /swapfile none swap sw 0 0 /etc/fstab这套命令生成一个2G的swapfile文件重启后自动挂载。注意chmod 600不能省不然系统会警告并拒绝使用。实际用下来Swap对防止突发高内存导致进程被杀很有帮助但如果你发现程序频繁消耗Swap那说明内存确实不够该升配置就升配置别硬扛。3. 数据库与缓存让数据有地方待3.1 MySQL的安装与初始化数据库选型这个问题中小项目我基本都推荐MySQL生态太成熟了遇到问题随便一搜都是解决方案。PostgreSQL也很优秀尤其在某些JSON查询和地理数据场景更强但日常业务MySQL足够。Debian 12默认仓库里的MySQL版本是8.0直接用apt安装就好apt install -y mysql-server systemctl enable mysql systemctl start mysql装完之后跑一下安全初始化脚本mysql_secure_installation这个脚本会引导你设置root密码、删除匿名用户、禁止root远程登录。我建议全部选yes特别是禁止root远程登录因为数据库不应该暴露给公网。应用连接时单独创建业务账号权限只给需要的库表这样就算应用被攻破攻击者也拿不到整个数据库的控制权。创建数据库和用户的命令大致这样CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER appuserlocalhost IDENTIFIED BY 一个强密码; GRANT ALL PRIVILEGES ON myapp.* TO appuserlocalhost; FLUSH PRIVILEGES;这里用utf8mb4字符集因为MySQL 8的默认utf8mb4_0900_ai_ci虽然也挺好但utf8mb4_unicode_ci兼容性更稳特别是在排序规则上不会出现意外。如果应用已经有现存数据导入之前别忘了确认源库的字符集一致不然中文变问号。3.2 Redis的部署和几个参数Redis在项目里通常干三件事缓存、分布式锁、临时会话存储。装起来很简单apt install -y redis-server但默认配置不能直接用。第一要改bind地址默认127.0.0.1就对了千万别改成0.0.0.0否则任何人都能连接。第二要设置requirepass给Redis加密码这样即使有人通过SSH隧道或内网跳板进来也无法直接操作数据。第三记得把appendonly yes打开开启AOF持久化确保重启后缓存数据不丢。我用Redis最大的感触是监控很重要。线上出了性能问题先看缓存命中率。REDIS自带INFO命令能看瞬时状态要长期监控可以用Prometheus加redis_exporter但小项目手动看就够了。注意的是别把Redis当数据库存核心业务数据它的定位就是快、易失、可重建架构设计上要接受这个事实。4. 项目部署实操从代码到跑起来4.1 代码上传的几种方式部署第一步是把代码弄到服务器上。最常见的有三种方式git clone、scp/rsync、和用GitHub Actions做CI自动部署。从远程仓库直接clone是我最推荐的方式。服务器上装好git然后git clone 你的仓库地址 /opt/myapp这样做的好处是后续更新代码不用全量上传进到目录里git pull就行。如果代码在私有仓库需要在服务器上生成一个新的SSH密钥对把公钥加到平台账号的Deploy Keys里。注意Deploy Keys最好只给只读权限不要给写权限。scp适合临时传个文件比如配置文件、证书。rsync适合同步目录它只传变更部分效率比scp高太多。比如把本地构建好的前端dist目录同步到服务器上rsync -avz --delete dist/ root服务器IP:/opt/frontend/--delete参数会让远端多出的文件也一并删除保证两端一致。这个在做前端发布时特别好用。4.2 进程守护让程序自己活着程序跑起来容易难的是崩溃之后还能自动恢复。我最早部署时图省事用nohup进程一崩可能一整天没人发现等用户反馈才知道。后面用了systemd和PM2之后这套痛点才算解决。如果项目是Node.js、Python这类解释型语言PM2很顺手npm install -g pm2 pm2 start app.js --name myapp pm2 save pm2 startuppm2 startup会生成一条开机自启命令pm2 save保存当前进程列表。这样服务器重启后你的应用也会自己跟着起来。PM2自带的日志管理也方便pm2 logs能直接看实时输出对排查问题非常有效率。如果项目是Java的Spring Boot或者Golang编译好的二进制我更推荐直接写systemd服务单元文件。举个例子在/etc/systemd/system/myapp.service里写[Unit] DescriptionMyApp Server Afternetwork.target [Service] Userwww-data WorkingDirectory/opt/myapp ExecStart/usr/bin/java -jar /opt/myapp/myapp.jar Restarton-failure RestartSec5 EnvironmentSPRING_PROFILES_ACTIVEprod [Install] WantedBymulti-user.target保存之后systemctl daemon-reload再systemctl enable --now myapp服务就起来了。其中Restarton-failure和RestartSec5很关键进程异常退出五秒后自动拉起Restertalways会连你手动停止时也拉起来反而麻烦。这里有一个重要提醒生产环境不要用开发模式启动服务。比如Spring Boot的spring-boot-devtoolsVite的dev模式都是为本地调试设计的既消耗资源又有安全风险。上线前一定构建成产线版本用java -jar或pm2 start类似命令跑编译产物。4.3 Nginx反向代理与域名绑定应用默认监听的端口往往不好记比如Spring Boot是8080Node是3000而且直接暴露业务端口既不安全也不专业。我在前面加一层Nginx做反向代理对外只开放80和443端口先按端口把请求转到内部服务上。安装Nginx之后在/etc/nginx/sites-available/下建配置文件然后软链到sites-enabled。一个前端加后端分离的配置大致是这样server { listen 80; server_name yourdomain.com; root /opt/frontend; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }配置完成后nginx -t检查语法然后systemctl reload nginx生效。这里注意location /api/转发时proxy_pass后面的URI规则决定了路径怎么替换。如果你写成http://127.0.0.1:8080会把完整的/api/xxx传给后端写成带斜杠的http://127.0.0.1:8080/则会去掉/api前缀。这个区别很多新手分不清我一开始踩过坑后端接口路径全对不上。域名解析方面在DNS服务商那加一条A记录指向服务器公网IP然后等待解析生效。想上HTTPS就用certbot申请证书apt install -y certbot python3-certbot-nginx certbot --nginx -d yourdomain.comcertbot会自动修改Nginx配置并加入证书路径也能配置自动续期。现在全站HTTPS是基础要求搜索引擎和浏览器都会给没证书的站点标记不安全所以这一步别省。5. 日常运维与排错把坑提前填平5.1 常见故障排查实录程序跑起来只是开始真正考验人的是它挂了之后你能不能快速定位。我把自己遇到最多的几类问题整理一下基本覆盖了日常运维的80%场景。第一个是端口被占用。特别常见于你改了配置重启服务发现提示bind失败。先用ss -lntp查看端口占用情况找到PID后用ps查是什么进程然后决定是kill还是换端口。注意不要什么都不看就直接kill有时候占用端口的可能是旧实例杀掉正好。第二个是内存耗尽导致进程被OOM Killer干掉。跑一个Java应用的时候非常明显日志里能看到Killed但一开始不知道谁干的。用dmesg | grep -i oom能看到内核杀进程的记录。要判断是内存真不足还是泄漏可以先top按内存排序看一眼再用jstat或pmap之类工具查详细情况。临时方案是加Swap但根本方案确实得优化代码或者升配置。第三个是磁盘满了。之前我遇到过MySQL突然写不进去报错全是“No space left on device”。排查下来是日志文件把磁盘占满了。df -h确认分区情况du -sh *找到大目录清理完再返回业务就能恢复。为了避免再发生我把日志切割和定期清理脚本写进了crontab每天凌晨跑一次。这三个是高频问题但每个人服务器上跑的东西不同具体原因可能五花八门。排查时养成良好的习惯第一步看日志不要瞎猜。systemd服务用journalctl -u 服务名 -fDocker容器用docker logs 容器名普通进程看nohup.out或者应用自己的日志文件。日志里一般会直接告诉你错误在哪个模块。5.2 备份策略与日常巡检备份这件事越早做越省钱。我给自己定的策略是“每天增量、每周全量、每月异地”。数据量小的时候全量备份每天做也扛得住。MySQL备份最简单的方式是用mysqldumpmysqldump -u root -p 数据库名 /backup/backup-$(date %F).sql恢复时mysql -u root -p 数据库名 backup.sql就行。但这里有个坑mysqldump默认会锁表如果线上数据量大或对一致性要求高最好使用--single-transaction参数做在线备份避免影响业务。备份文件别留在系统盘上不然磁盘满了会反噬。上传到对象存储或另一个服务器是最稳的做法。我记得有次系统盘整块故障项目文件和备份都在同一块盘上直接全没这种教训一次就够。日常巡检方面我列了个小清单每天看一眼磁盘使用率超过80%就该清理每周检查一次服务状态确保systemd或PM2里没有连续崩溃的进程定期更新系统安全补丁检查定时备份任务是否执行成功留意CPU负载和内存走势提前扩容这些用眼睛看也行想省事可以写一个简单的Shell脚本把df、free、uptime、systemctl status的结果打到文件或发到告警机器人。下面是一个很简化的示例#!/bin/bash echo $(date) df -h | grep -E Filesystem|/dev free -h uptime systemctl is-active myapp放到crontab里每半小时执行一次输出到日志自己心里有数。5.3 从裸机到上线的时间线复盘按我这次的完整流程把时间线列一下方便你做项目排期心里有谱第1小时初始化机器、SSH登录、基础安全加固、换源第2小时安装运行环境配置镜像源和基础软件包第3小时安装数据库和缓存初始化账号和表结构第4小时上传代码或克隆仓库启动应用并接入systemd第5小时配置Nginx反向代理绑定域名并申请HTTPS证书第6小时全链路测试从外部访问完整功能后续写备份脚本、做巡检计划、看日志持续优化整个过程如果是一次性到位熟练的人两三个小时就能完成。但真正发上线公告之前我觉得至少留出半天到一天的时间做回归测试和压测因为线上环境和本地环境总是会有细微差别比如时区、字符集、内存分配、文件权限任何一个都会成为线上事故的导火索。我个人在多次部署中感触最深的一点是规范化的流程比灵光一闪的天才操作更可靠。把每一步都写进文档下次换一台服务器、换一个项目时照着流程走就不会漏步骤。服务器运维这件事功夫都在平时把基础打牢后面的运行维护就会轻松很多。