1. 项目缘起为什么从零开始搭建服务器最近在帮一个朋友部署他的个人项目他之前一直用一些免费的云服务或者本地跑跑现在想正式上线拥有一个稳定、可控的线上环境。他问我“是不是买个云服务器装个宝塔面板就完事了” 我告诉他宝塔确实方便但如果你想真正理解一个项目从开发到上线的完整链路想拥有更灵活、更可控、更“DevOps”一点的部署方式从零开始手动搭建环境再用Docker容器化部署是绕不开的一课。这不仅仅是“部署”而是一次对现代应用部署流程的深度实践。这个“从零到一”的过程涵盖了Linux服务器基础操作、网络与安全配置、服务安装与编排、容器化技术应用等多个环节。它解决的问题很直接让你亲手将一个“裸”的云服务器变成一个能稳定、安全运行你业务应用的“生产环境”。无论你是个人开发者想部署自己的博客、工具站还是小团队需要搭建测试或生产环境这套流程都极具参考价值。它让你摆脱对集成面板的依赖真正掌控你的服务器并且在未来面对更复杂的微服务架构时也能游刃有余。2. 环境准备选择与初始化你的云服务器2.1 云服务商与服务器选型第一步是选择云服务商和服务器。国内主流的有阿里云、腾讯云、华为云等国外有AWS、DigitalOcean、Vultr等。选择时主要考虑地理位置影响访问延迟、价格、易用性和社区支持。对于个人项目或小型应用我通常建议从最基础的配置开始。以腾讯云轻量应用服务器为例1核2G的配置对于初期流量不大的Web应用、API服务或博客系统完全够用。操作系统选择上强烈推荐 Ubuntu 22.04 LTS。LTS代表长期支持稳定性和社区支持都更好。CentOS曾经是主流但Red Hat改变了其策略后Ubuntu Server成为了更普适和友好的选择。购买后你会获得服务器的公网IP地址、root用户名和密码或密钥对。这是你通往服务器世界的钥匙。2.2 首次登录与基础安全加固拿到服务器后第一件事不是急着装软件而是做好安全加固。通过SSH连接服务器ssh root你的服务器公网IP输入密码或使用密钥对登录。登录后立即进行以下几项操作更新系统包apt update apt upgrade -y。确保系统所有软件包都是最新的修复已知安全漏洞。创建新用户永远不要长期使用root用户操作。创建一个具有sudo权限的普通用户。adduser yourusername usermod -aG sudo yourusername配置SSH密钥登录禁用密码登录这是防止暴力破解的关键。在你的本地电脑生成SSH密钥对如果还没有ssh-keygen -t rsa -b 4096。然后将公钥~/.ssh/id_rsa.pub的内容复制到服务器的~/.ssh/authorized_keys文件中。接着编辑SSH配置文件/etc/ssh/sshd_config将PasswordAuthentication设置为no。将PermitRootLogin设置为prohibit-password或no如果你确定不用root登录。可以修改Port为其他非22端口如2222以增加隐蔽性但这并非必需密钥认证已足够安全。 修改后重启SSH服务systemctl restart sshd。务必在重启前测试用新用户和密钥能否登录否则可能把自己锁在门外。配置防火墙Ubuntu默认使用ufwUncomplicated Firewall。启用它并放行必要的端口。ufw allow 22/tcp # SSH端口如果你改了端口这里要对应修改 ufw allow 80/tcp # HTTP ufw allow 443/tcp # HTTPS ufw --force enable # 启用防火墙 ufw status verbose # 查看规则完成这些你的服务器就有了一个相对安全的基础。接下来我们开始安装核心服务。3. 核心服务安装为Docker铺平道路我们的目标是使用Docker部署项目但Docker本身需要一些依赖并且我们还需要一个反向代理服务器来管理流量。3.1 安装Docker与Docker ComposeDocker的安装官方文档非常清晰。我们使用官方提供的便捷脚本适用于测试和开发环境生产环境建议通过仓库安装# 安装必要工具 apt install -y apt-transport-https ca-certificates curl software-properties-common # 添加Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装Docker引擎 apt update apt install -y docker-ce docker-ce-cli containerd.io安装完成后启动Docker并设置开机自启systemctl start docker systemctl enable docker。为了不用每次都加sudo可以将当前用户加入docker组sudo usermod -aG docker $USER然后退出SSH重新登录生效。Docker Compose是一个用于定义和运行多容器Docker应用的工具。我们安装其独立版本v2# 下载最新稳定版Docker Compose DOCKER_CONFIG${DOCKER_CONFIG:-$HOME/.docker} mkdir -p $DOCKER_CONFIG/cli-plugins curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose # 赋予执行权限 chmod x $DOCKER_CONFIG/cli-plugins/docker-compose # 验证安装 docker compose version3.2 安装Nginx作为反向代理虽然我们可以用Docker运行Nginx但我更倾向于在宿主机上安装一个Nginx作为“流量总入口”。这样做有几个好处管理证书方便用Certbot、配置统一、不依赖Docker网络即使所有容器重启反向代理依然在。当然这只是一个选择你也可以完全容器化。安装Nginx很简单apt install -y nginx。安装后其配置文件在/etc/nginx目录下。我们先保持默认稍后再配置。4. 项目容器化编写Dockerfile与Compose文件假设我们有一个简单的Python Flask Web应用项目结构如下myapp/ ├── app.py ├── requirements.txt └── Dockerfileapp.py是应用主文件requirements.txt列出了依赖如Flask2.3.2。4.1 编写DockerfileDockerfile是构建镜像的蓝图。一个典型的Python应用Dockerfile如下# 使用官方Python精简版作为基础镜像 FROM python:3.11-slim # 设置工作目录 WORKDIR /app # 复制依赖文件并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 暴露端口Flask默认5000 EXPOSE 5000 # 定义容器启动命令 CMD [python, app.py]这个Dockerfile做了几件事从一个干净的基础镜像开始设置容器内的工作路径先复制依赖文件并安装利用Docker层缓存如果requirements.txt不变这层会被缓存加速后续构建再复制所有代码声明容器运行时监听的端口最后指定启动命令。4.2 编写Docker Compose文件对于单服务似乎用docker build和docker run就够了。但Compose文件docker-compose.yml的优势在于它能以声明式的方式定义整个应用栈服务、网络、卷并且便于管理。即使只有一个服务我也推荐使用Compose因为配置更清晰且易于未来扩展比如加入数据库。在项目根目录创建docker-compose.ymlversion: 3.8 services: webapp: build: . container_name: my_flask_app ports: - 5000:5000 environment: - FLASK_ENVproduction restart: unless-stopped volumes: - ./logs:/app/logs这个配置定义了一个名为webapp的服务使用当前目录的Dockerfile构建镜像将容器命名为my_flask_app将宿主机的5000端口映射到容器的5000端口设置环境变量设置重启策略除非手动停止否则异常退出会自动重启挂载一个卷将宿主机当前目录下的logs文件夹映射到容器的/app/logs用于持久化日志。注意这里将端口直接映射到宿主机只是为了测试方便。在生产部署中我们通常不会直接将应用端口暴露给公网而是通过宿主机上的Nginx反向代理来访问因此Compose文件中可以去掉ports映射或者只映射到127.0.0.1:5000:5000。5. 部署与上线整合Nginx与HTTPS5.1 构建并运行容器在服务器上将你的项目代码上传可以用Git克隆或用scp命令。进入项目目录运行docker compose up -d --build-d代表后台运行--build表示在启动前重新构建镜像。执行后使用docker compose ps查看服务状态docker compose logs -f webapp查看实时日志。此时你的应用应该已经在容器内运行并监听5000端口。你可以在服务器上执行curl http://localhost:5000测试是否正常响应。5.2 配置Nginx反向代理现在我们需要让外网用户能通过80/443端口访问我们的应用。编辑Nginx的站点配置文件通常放在/etc/nginx/sites-available/然后软链接到/etc/nginx/sites-enabled/。创建配置文件/etc/nginx/sites-available/myappserver { listen 80; server_name yourdomain.com www.yourdomain.com; # 替换为你的域名 location / { proxy_pass http://127.0.0.1:5000; # 指向Docker容器应用 proxy_set_header Host $host; 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; } # 可选的静态文件服务如果你的应用有静态文件 # location /static/ { # alias /path/to/your/static/files; # expires 30d; # } }关键点在于proxy_pass指令它将所有到达Nginx 80端口的请求转发给了本机127.0.0.1的5000端口也就是我们Docker容器内应用监听的端口通过之前的端口映射暴露给了宿主机。创建软链接并测试配置ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ nginx -t # 测试配置文件语法 systemctl reload nginx # 重载配置不中断服务现在通过浏览器访问你的服务器公网IP或域名如果域名已解析应该就能看到你的应用了。5.3 使用Certbot获取并配置HTTPS证书在当今HTTPS是必须的。Let‘s Encrypt提供了免费的SSL/TLS证书我们可以用Certbot工具自动化获取和续期。安装Certbot和Nginx插件apt install -y certbot python3-certbot-nginx然后运行Certbot它会自动读取你的Nginx配置列出server_name并引导你完成证书申请和Nginx配置更新certbot --nginx按照提示操作选择你要申请证书的域名并选择是否将HTTP流量重定向到HTTPS强烈建议选择是。成功后Certbot会自动修改你的Nginx配置文件添加SSL相关配置并设置自动续期任务。完成后再次访问你的域名地址栏应该显示安全的HTTPS连接。你的Nginx配置也会被Certbot更新类似于server { listen 443 ssl http2; server_name yourdomain.com www.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # ... 其他SSL配置由Certbot自动管理 ... location / { proxy_pass http://127.0.0.1:5000; # ... proxy_set_header 配置 ... } } server { listen 80; server_name yourdomain.com www.yourdomain.com; return 301 https://$server_name$request_uri; # HTTP重定向到HTTPS }6. 生产环境考量与进阶优化至此一个基本的“从零到一”部署流程已经完成。但对于真正的生产环境我们还需要考虑更多。6.1 使用独立的Docker网络默认情况下Compose会为你的项目创建一个独立的桥接网络。但为了更精细的控制或者让多个Compose项目间的容器能安全通信可以定义自定义网络。在docker-compose.yml中networks: app-network: driver: bridge services: webapp: # ... 其他配置 ... networks: - app-network然后在Nginx的proxy_pass中可以使用Compose服务名作为主机名前提是Nginx也在同一个网络中可以将宿主机Nginx也容器化或者使用host网络模式。对于宿主机Nginx继续使用127.0.0.1即可。6.2 数据持久化与备份如果你的应用有数据库如MySQL、PostgreSQL务必使用**命名卷Named Volume或绑定挂载Bind Mount**来持久化数据防止容器删除后数据丢失。在docker-compose.yml中为数据库服务添加卷services: db: image: mysql:8.0 volumes: - db_data:/var/lib/mysql # 命名卷 - ./mysql/conf.d:/etc/mysql/conf.d:ro # 绑定挂载只读配置文件 environment: MYSQL_ROOT_PASSWORD: your_strong_password volumes: db_data: # 声明命名卷对于重要的数据卷需要建立定期备份机制可以使用cron任务执行docker run --rm -v db_data:/volume -v /path/to/backup:/backup alpine tar czf /backup/backup-$(date %Y%m%d).tar.gz -C /volume ./之类的命令。6.3 日志管理与监控Docker默认的日志驱动是json-file日志会存储在宿主机的/var/lib/docker/containers/下。对于生产环境可以考虑配置日志轮转在/etc/docker/daemon.json中配置log-driver和log-opts限制日志文件的最大大小和数量。{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }使用集中式日志将容器日志发送到ELKElasticsearch, Logstash, Kibana或Loki等日志聚合系统。基础监控使用docker stats命令查看容器资源使用情况或部署开源的监控方案如Prometheus Grafana配合cAdvisor收集容器指标。6.4 使用.env文件管理敏感信息绝对不要在docker-compose.yml中硬编码密码、密钥等敏感信息。应该使用环境变量文件.env。在项目根目录创建.env文件MYSQL_ROOT_PASSWORDyour_very_strong_password_here SECRET_KEYyour_flask_secret_key在docker-compose.yml中引用services: webapp: # ... environment: - SECRET_KEY${SECRET_KEY} db: # ... environment: - MYSQL_ROOT_PASSWORD${MYSQL_ROOT_PASSWORD}将.env文件添加到.gitignore中确保不会被提交到版本库。在服务器上单独维护这个文件。6.5 实现CI/CD自动化手动上传代码、构建、重启容器效率低下。可以结合GitHub Actions、GitLab CI/CD或Jenkins等工具实现自动化部署。基本流程是代码推送到特定分支如main → CI/CD平台检测到变更 → 在平台上或通过SSH连接到你的服务器 → 拉取最新代码 → 执行docker compose up -d --build→ 完成部署。一个简单的GitHub Actions工作流示例.github/workflows/deploy.ymlname: Deploy to Server on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkoutv3 - name: Deploy via SSH uses: appleboy/ssh-actionv0.1.5 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /path/to/your/project git pull origin main docker compose up -d --build需要在GitHub仓库的Settings - Secrets中配置SERVER_HOST、SERVER_USER和SSH_PRIVATE_KEY。走完这一整套流程你收获的不仅仅是一个在线的项目更是一套可复用的、对现代应用部署的深刻理解。从最基础的服务器安全到服务编排再到反向代理和自动化每一步都踩得踏实未来无论项目复杂度如何增长你都有足够的知识储备去应对和扩展。