Technical Tutorials
Build a Personal Blog on a VPS (2025) - WordPress/Typecho/Hugo Complete Solutions
Three mainstream approaches to building a personal blog on a VPS in 2025: WordPress, Typecho, and Hugo. This article provides detailed Docker deployment tutorials and an HTTPS configuration guide to help you easily own an independent blog.

In 2025, even though platforms like WeChat Official Accounts, Zhihu, and Xiaohongshu have enormous traffic, owning a fully independent blog of your own remains a fixation for many people. It represents data sovereignty, unrestrained expression, and the romance of the technically minded.
This article provides three mainstream approaches to building a personal blog on a VPS: WordPress (powerful), Typecho (lightweight and simple), and Hugo (geeky static), along with the latest 2025 Docker deployment tutorials.
| Feature | WordPress | Typecho | Hugo |
|---|---|---|---|
| Type | Dynamic CMS | Dynamic CMS | Static site generator (Static) |
| Learning curve | ⭐ (Easiest) | ⭐⭐ (Easy) | ⭐⭐⭐⭐ (Has a barrier) |
| Resource usage | High (1G+ RAM recommended) | Low (runs on 512MB) | Extremely low (pure static files) |
| Plugin ecosystem | ⭐️⭐️⭐️⭐️⭐️ (Massive) | ⭐️⭐️⭐️ (Sufficient) | ⭐️⭐️ (Manual configuration required) |
| Security | Requires frequent patch updates | Relatively good | ⭐️⭐️⭐️⭐️⭐️ (No database, safest) |
| Suitable for | People who don't want to tinker with code and want ready-made themes and features | People who like minimalist style and focus only on writing | Geeks and programmers who like managing content with Git |
WordPress is the world's most popular CMS, with countless themes and plugins.
Deployment steps:
-
Create the directory:
mkdir wordpress && cd wordpress -
Create
docker-compose.yml:Security tip: We bind the web port to
127.0.0.1, allowing only the local Caddy to access it, avoiding direct port exposure to the public internet and improving security.services: db: image: mariadb:10.11 container_name: wp-db restart: always environment: MYSQL_ROOT_PASSWORD: your_strong_root_password # 请务必修改为强密码 MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: your_strong_db_password # 请务必修改为强密码 volumes: - db_data:/var/lib/mysql wordpress: image: wordpress:latest container_name: wp-app restart: always ports: - "127.0.0.1:8080:80" # 仅监听本地,配合 Caddy 反代 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: your_strong_db_password # 与上面保持一致 WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html depends_on: - db redis: # 可选:用于对象缓存加速 image: redis:alpine container_name: wp-redis restart: always volumes: db_data: wp_data: -
Start the service:
docker compose up -d -
Configuration recommendations:
- After completing the Caddy configuration, visit
https://你的域名to finish the installation. - Strongly recommended: Install the "Redis Object Cache" plugin, set the connection address to
redis, which can significantly improve backend loading speed.
- After completing the Caddy configuration, visit
Typecho is a very popular lightweight blogging system in China, with native Markdown support, a simple structure, and blazing-fast performance.
Deployment steps:
-
Create the directory:
mkdir typecho && cd typecho -
Create
docker-compose.yml(using the PHP-FPM + Nginx combination):services: typecho: image: joyqi/typecho:nightly-php7.4-fpm-alpine container_name: typecho-app restart: always environment: TYPECHO_DB_HOST: db TYPECHO_DB_USER: typecho TYPECHO_DB_PASSWORD: your_strong_db_password TYPECHO_DB_DATABASE: typecho volumes: - typecho_data:/var/www/html depends_on: - db nginx: image: nginx:alpine container_name: typecho-nginx restart: always ports: - "127.0.0.1:8081:80" # 仅监听本地 volumes: - typecho_data:/var/www/html - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - typecho db: image: mariadb:10.11 container_name: typecho-db restart: always environment: MYSQL_ROOT_PASSWORD: your_strong_root_password MYSQL_DATABASE: typecho MYSQL_USER: typecho MYSQL_PASSWORD: your_strong_db_password volumes: - db_data:/var/lib/mysql volumes: typecho_data: db_data: -
Create
nginx.conf:server { listen 80; server_name localhost; root /var/www/html; index index.php index.html; # 屏蔽敏感文件 location ~ ^/(\.user.ini|\.htaccess|\.git|admin/config.inc.php) { deny all; } location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { fastcgi_pass typecho:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } -
Start the service:
docker compose up -d
Hugo is not a program that runs on the VPS; instead, it generates HTML files on your local computer, which you then upload to the VPS.
Workflow:
- Local (Mac/PC): Write Markdown -> run the
hugocommand -> generate thepublicfolder. - VPS: Run a web server (Caddy/Nginx) to host the HTML files.
- Publish: Use
rsyncorscpto sync the localpublicfolder to the VPS.
VPS-side deployment (Docker Caddy):
-
Create the directory:
mkdir myblog -
Create
docker-compose.yml:services: caddy: image: caddy:alpine container_name: blog-server restart: always ports: - "80:80" # Caddy 需要公开 80/443 以申请证书 - "443:443" volumes: - ./public:/usr/share/caddy # 映射网页文件目录 - caddy_data:/data - caddy_config:/config volumes: caddy_data: caddy_config: -
Start the service:
docker compose up -d -
Upload content (execute on your local computer):
# 假设你的 VPS IP 是 1.2.3.4,目录是 /root/myblog/public rsync -avz --delete ./public/ [email protected]:/root/myblog/public/
For WordPress and Typecho, we also recommend using Caddy as a reverse proxy to handle HTTPS.
Key preparation steps (must-read):
- Domain resolution: Be sure to first go to your domain registrar (such as Alibaba Cloud, Namecheap) and point the domain's A record to the VPS IP address.
- Wait for propagation: Ping the domain in your local terminal, and you must ensure the IP has already changed. If the domain isn't resolved properly when Caddy starts, the SSL certificate application will fail outright, making the site inaccessible.
Caddyfile example:
# WordPress 反代
blog.yourdomain.com {
reverse_proxy localhost:8080
}
# Typecho 反代
note.yourdomain.com {
reverse_proxy localhost:8081
}
After starting Caddy, it automatically applies for and renews certificates, with no manual intervention needed.
Many beginners easily overlook this, but on a VPS, data backup is life. Once the VPS provider disappears or the server fails, having no backup means all your articles are gone.
- Backup directory: All Docker configurations in this article mount data to
volumes. You need to regularly back up the/var/lib/docker/volumesdirectory. - Automated backup: Manual backups are easy to forget, so we strongly recommend referring to our previous article VPS Automated Backup Solutions (2025) and using Rclone to automatically sync data to Google Drive or an S3 bucket, so you can sleep soundly.
- WordPress: The strongest ecosystem, suitable for users who don't want to tinker and have many feature requirements.
- Typecho: Light, fast, and simple, suitable for pure writing.
- Hugo: Secure, blazing-fast, and database-free, suitable for tech enthusiasts.
No matter which solution you choose, content is always the core of a blog.