Vercel迁移到Dokploy自部署,每月立省20刀

前言

最近做的一个网站流量稍微起来一些了,把Vercel的免费额度用完了,为了让网站正常运转,开了Vercel的Pro,一个月20刀,有点小贵,就琢磨琢磨着自部署省点钱。

研究了两天把整个流程跑通了,还有一些踩坑的点,记录一下帮助下有同样需求的人。

服务器设置

要自部署得先有一台服务器,官方推荐服务器至少要2G的内存和30G的磁盘空间。

To ensure a smooth experience with Dokploy, your server should have at least 2GB of RAM and 30GB of disk space. This specification helps to handle the resources consumed by Docker during builds and prevents system freezes. 官方安装文档

我在腾讯云买了一台199/年(差不多一个多月Vercel的订阅费用)的在硅谷的2核4G内存60G磁盘的机器,海外机器部署服务不用备案,不用担心买国内云服务商的机器需要备案,不过这个机器每个用户限购一台,对我来说够用了,想要参考的也可以看看。

服务器的系统按官方的推荐选择了Ubuntu 22.04 LTS。

部署Dokploy

直接执行脚本安装Dokploy:

arduino 复制代码
curl -sSL https://dokploy.com/install.sh | sh

安装完成后,需要在防火墙打开3000端口,如下配置即可:

然后访问: http://你服务器的ip:3000

设置你的管理员的账号密码即可。

如果不想通过ip访问也可以绑定域名,点击左侧的Web Server设置你的域名即可,这个地方可以使用你某个域名的子域名即可。

然后在你的域名DNS解析中增加一条A记录,把对应的子域名解析到服务器IP。

这样就可以直接通过子域名访问Dokploy的管理界面了。

项目部署

Dokploy部署完成后,可以开始部署项目了。

Github配置

首先配置需要配置好Git仓库,方便Dokploy去拉取代码部署。

点击左侧的Git菜单,选择Github,点击创建Github App。

创建完成后,点击去授权,并选择你需要的仓库或者所有仓库,这样Dokploy就能获取Github的代码仓库了。

接下来还需要配置一下Github token和Registry,这个配置是为了让Dokploy能从Github拉取你使用Github Actions构建的镜像进行部署,推荐使用这种方式,这样可以避免使用你的服务器进行打包镜像,减轻你服务器的压力,要是你服务器很屌可以不用操作这个配置,直接在服务器上构建部署就行。

首先需要新建一个Github Token,然后勾选write:packages权限,创建Token的URL:

github.com/settings/to...

然后复制Token,到Dokploy中点击左侧Registry菜单,点击新增,username是你的Github账号吗,Password是刚才复制的Token,Registry URL是:ghcr.io

项目创建及部署

在Dokploy管理后台的Projects中先创建Project再创建Service,Service才是对应的Vercel中的项目,Dokploy的Project下可以有多个Service。

接下来就可以部署了。

Github Actions构建,Dokploy部署(推荐)

先讲比较推荐的部署方式,使用Github Actions构建镜像,然后Dokploy使用Docker Provider的方式部署。

这种方式镜像的构建不在你的服务器上,而是白嫖了Github Actions来帮忙构建,对于配置不高的服务器来说很有用。

首先需要在你要部署的代码仓库中添加Github Actions的工作流配置,在根目录中创建文件:.github/workflow/docker-image.yml,内容如下:

yaml 复制代码
# https://docs.github.com/zh/actions/use-cases-and-examples/publishing-packages/publishing-docker-images
name: Create and publish a Docker image

# Configures this workflow to run every time a change is pushed to the branch called `release`.
on:
  push:
    branches: ['main']

# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
      # 
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
      - name: Log in to the Container registry
        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      - name: Build and push Docker image
        id: push
        uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            NEXT_PUBLIC_WEB_URL=${{ secrets.NEXT_PUBLIC_WEB_URL }}
            NEXT_PUBLIC_PROJECT_NAME=${{ secrets.NEXT_PUBLIC_PROJECT_NAME }}

      # Trigger redeploy on dokploy => project webhooks settings
      - name: Trigger dokploy redeploy
        run: |
          curl -X GET https://dokploy.test.com/api/deploy/ZdYZjoiNxZ5nDIbjO1E2x
      

这个配置文件中有两点需要注意的:

  1. 构建镜像时的build-args,如果你没有NEXT_PUBLIC_*变量需要设置可以删去,如果有就修改成你自己的变量名,并在Github对应仓库的settings中增加secret变量
  1. 最后的curl请求的链接需要替换成对应Dokploy上项目的部署Webhook URL

然后在根目录上新增构建的Dockerfile

bash 复制代码
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat && yarn global add pnpm

WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json pnpm-lock.yaml* ./
RUN pnpm i --frozen-lockfile

# Rebuild the source code only when needed
FROM deps AS builder

WORKDIR /app

# -----------------------------------------------------------------------------
# Build Arguments for NEXT_PUBLIC_* variables
# -----------------------------------------------------------------------------
ARG NEXT_PUBLIC_WEB_URL
ARG NEXT_PUBLIC_PROJECT_NAME

# Set environment variables for build
ENV NEXT_PUBLIC_WEB_URL=${NEXT_PUBLIC_WEB_URL}
ENV NEXT_PUBLIC_PROJECT_NAME=${NEXT_PUBLIC_PROJECT_NAME}

COPY . .
RUN pnpm build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs && \
    mkdir .next && \
    chown nextjs:nodejs .next

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV NODE_ENV production
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"

CMD ["node", "server.js"]

这个文件中需要修改环境变量,改为你自己的环境变量即可,和上面的Github Actions的构建文件中的变量对应。

ini 复制代码
ARG NEXT_PUBLIC_WEB_URL
ARG NEXT_PUBLIC_PROJECT_NAME

# Set environment variables for build
ENV NEXT_PUBLIC_WEB_URL=${NEXT_PUBLIC_WEB_URL}
ENV NEXT_PUBLIC_PROJECT_NAME=${NEXT_PUBLIC_PROJECT_NAME}

接下来就可以在Dokploy进行部署了。 打开需要部署的项目,Provider选择Docker,Docker Image参数填:ghcr.io/[Github账号名]/[Repository项目名]:[分支名]

如果有环境变量需要设置,可以点击Environment,然后设置环境变量即可。

设置完成后,点击Deploy部署即可。

然后可以在Deployments中查看是否部署成功,以及如果部署失败的日志。

部署成功后,可以在Domain菜单中给服务绑定域名,这样就可以通过域名来访问对应的服务了,从Vercel迁移过来的时候,先使用一个子域名进行测试,如果没问题再切换到正式域名上。

服务绑定域名后,去给域名增加一条DNS解析,我这里是使用的cloudflare。

搞定之后,你就可以通过你域名访问你刚刚部署的服务了。

Dokploy构建并部署

如果你的服务器配置比较好,也可以直接使用Dokploy进行部署。 打开项目,Provider选择Github,Github Account选择之前配置的账号,Repository选择要部署的仓库。

Build Type选择Dockerfile,保存后,选择部署即可。

总结

自己实操下来使用Dokploy自己部署项目还是很简单的,我中间只被项目的变量设置卡了一下,其他的都很顺利。

买个服务器花了199/年,Vercel一个月订阅就要20美元,一年还是能省不少钱的。

相关推荐
day>day>up12 分钟前
django uwsgi启动报错failed to get the Python codec of the filesystem encoding
后端·python·django
Livingbody25 分钟前
FastMCP In Action跑通第一个MCP之跟学python版
后端
bobz96544 分钟前
QT 中的三种基本UI类型:Main Window | Widget | Dialog
后端
zhoupenghui1681 小时前
golang实现支持100万个并发连接(例如,HTTP长连接或WebSocket连接)系统架构设计详解
开发语言·后端·websocket·golang·系统架构·echo·100万并发
咸甜适中1 小时前
Rust语言序列化和反序列化vec<u8>,serde库Serialize, Deserialize,bincode库(2025年最新解决方案详细使用)
开发语言·后端·rust
JiaHao汤2 小时前
Java 虚拟机之双亲委派机制
java·jvm·后端
哈基米喜欢哈哈哈2 小时前
Uber的MySQL实践(一)——学习笔记
数据库·笔记·后端·mysql
姑苏洛言3 小时前
扫码点餐小程序产品需求分析与功能梳理
前端·javascript·后端
Java技术小馆4 小时前
PromptPilot打造高效AI提示词
java·后端·面试