跳转至

自托管部署

在自己的服务器上部署 Zensical 网站

什么是自托管?

自托管是指在自己的服务器(VPS、云服务器等)上部署网站,拥有完全的控制权:

  • 完全控制 - 自由配置服务器
  • 无限制 - 没有流量和存储限制
  • 高性能 - 可以优化服务器性能
  • 隐私保护 - 数据完全在自己掌控中

准备工作

在开始之前,你需要:

  • 一台 Linux 服务器(Ubuntu/Debian/CentOS)
  • 服务器的 SSH 访问权限
  • 域名(可选,但推荐)
  • 基本的 Linux 命令知识

方法一:使用 Nginx 部署(推荐)

第一步:构建网站

在本地构建网站:

zensical build

这会在 site/ 目录生成静态文件。

第二步:上传文件到服务器

使用 scprsync 上传文件:

# 使用 scp
scp -r site/* user@your-server:/var/www/your-site/

# 使用 rsync(推荐,支持增量同步)
rsync -avz --delete site/ user@your-server:/var/www/your-site/

第三步:安装 Nginx

在服务器上安装 Nginx:

# Ubuntu/Debian
sudo apt update
sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

第四步:配置 Nginx

创建 Nginx 配置文件 /etc/nginx/sites-available/your-site

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/your-site;
    index index.html;

    # 启用 gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript 
               application/x-javascript application/xml+rss 
               application/json application/javascript;

    # 主要位置配置
    location / {
        try_files $uri $uri/ =404;
    }

    # 缓存静态资源
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 404 页面
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}

第五步:启用站点

# 创建符号链接
sudo ln -s /etc/nginx/sites-available/your-site /etc/nginx/sites-enabled/

# 测试配置
sudo nginx -t

# 重启 Nginx
sudo systemctl restart nginx

第六步:配置 HTTPS(使用 Let's Encrypt)

安装 Certbot:

# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx

获取 SSL 证书:

sudo certbot --nginx -d example.com -d www.example.com

Certbot 会自动配置 HTTPS 并设置自动续期。

方法二:使用 Apache 部署

安装 Apache

# Ubuntu/Debian
sudo apt install apache2

# CentOS/RHEL
sudo yum install httpd

配置 Apache

创建配置文件 /etc/apache2/sites-available/your-site.conf

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/your-site

    <Directory /var/www/your-site>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # 启用压缩
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
    </IfModule>

    # 缓存控制
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresByType image/jpg "access plus 1 year"
        ExpiresByType image/jpeg "access plus 1 year"
        ExpiresByType image/gif "access plus 1 year"
        ExpiresByType image/png "access plus 1 year"
        ExpiresByType text/css "access plus 1 year"
        ExpiresByType application/javascript "access plus 1 year"
    </IfModule>

    ErrorLog ${APACHE_LOG_DIR}/your-site-error.log
    CustomLog ${APACHE_LOG_DIR}/your-site-access.log combined
</VirtualHost>

启用站点

# 启用站点
sudo a2ensite your-site

# 启用必要的模块
sudo a2enmod rewrite deflate expires

# 重启 Apache
sudo systemctl restart apache2

方法三:使用 Docker 部署

创建 Dockerfile

FROM nginx:alpine

# 复制构建文件
COPY site/ /usr/share/nginx/html/

# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

创建 nginx.conf

server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
}

构建和运行

# 构建镜像
docker build -t my-zensical-site .

# 运行容器
docker run -d -p 80:80 --name my-site my-zensical-site

使用 docker-compose

创建 docker-compose.yml

version: '3'

services:
  web:
    build: .
    ports:
      - "80:80"
    restart: unless-stopped

运行:

docker-compose up -d

自动化部署

使用 Git Hooks

在服务器上设置 Git 仓库:

# 创建裸仓库
mkdir -p /var/repo/your-site.git
cd /var/repo/your-site.git
git init --bare

# 创建 post-receive hook
cat > hooks/post-receive << 'EOF'
#!/bin/bash
GIT_WORK_TREE=/var/www/your-site git checkout -f
cd /var/www/your-site
zensical build
EOF

chmod +x hooks/post-receive

在本地添加远程仓库:

git remote add production user@your-server:/var/repo/your-site.git

部署:

git push production main

使用 GitHub Actions

创建 .github/workflows/deploy.yml

name: Deploy to Server

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Zensical
        run: pip install zensical

      - name: Build
        run: zensical build

      - name: Deploy to Server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          source: "site/*"
          target: "/var/www/your-site/"
          strip_components: 1

性能优化

启用 HTTP/2

在 Nginx 配置中:

listen 443 ssl http2;
listen [::]:443 ssl http2;

配置缓存

# 浏览器缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# Nginx 缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;

启用 Brotli 压缩

# 安装 Brotli 模块
sudo apt install nginx-module-brotli

# 在 Nginx 配置中启用
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml;

安全配置

配置防火墙

# UFW (Ubuntu)
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

# Firewalld (CentOS)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

配置 SSL 安全性

在 Nginx 配置中添加:

# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# 其他安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

监控和维护

日志管理

# 查看访问日志
sudo tail -f /var/log/nginx/access.log

# 查看错误日志
sudo tail -f /var/log/nginx/error.log

# 日志轮转
sudo logrotate -f /etc/logrotate.d/nginx

性能监控

使用工具如: - htop - 系统资源监控 - nginx-amplify - Nginx 性能监控 - Prometheus + Grafana - 全面监控方案

常见问题

权限问题

# 设置正确的权限
sudo chown -R www-data:www-data /var/www/your-site
sudo chmod -R 755 /var/www/your-site

404 错误

检查: 1. 文件路径是否正确 2. Nginx 配置中的 root 路径 3. index.html 是否存在

SSL 证书问题

# 测试证书续期
sudo certbot renew --dry-run

# 手动续期
sudo certbot renew

完整配置示例

Nginx 完整配置(带 HTTPS)

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    root /var/www/your-site;
    index index.html;

    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    error_page 404 /404.html;

    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
}

参考资料