Skip to content

Commit bbcdbde

Browse files
committed
feat: add Docker deployment blog post and repo README
Add tutorial on deploying Hype blogs with Docker covering Dokploy, Heroku, and generic VPS setups. Add README explaining repo purpose and development workflow. Closes #8
1 parent 5ed81db commit bbcdbde

2 files changed

Lines changed: 232 additions & 0 deletions

File tree

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# hypemd.dev
2+
3+
The official website and blog for [Hype](https://github.com/gopherguides/hype) — a dynamic Markdown engine that executes code, includes files, and validates content at build time.
4+
5+
**Live site:** [hypemd.dev](https://hypemd.dev)
6+
7+
## What's Here
8+
9+
- **Blog articles** — tutorials and guides in `content/`
10+
- **Documentation** — synced automatically from the [hype repo](https://github.com/gopherguides/hype) via a GitHub Actions workflow
11+
- **Site layouts** — templates in `layouts/`
12+
13+
## Development
14+
15+
The site is built with Hype's built-in blog generator.
16+
17+
```bash
18+
# Install hype
19+
brew install gopherguides/tap/hype
20+
21+
# Build the site
22+
hype blog build
23+
24+
# Serve locally with live reload
25+
hype blog serve
26+
```
27+
28+
## Deployment
29+
30+
The site is deployed via [Dokploy](https://dokploy.com) with autodeploy on push to main. The Dockerfile handles the full build-and-serve pipeline.
31+
32+
## Doc Sync
33+
34+
Documentation pages (`content/docs-*/`) are automatically synced from the hype repo. When docs change in `gopherguides/hype`, a workflow processes them and pushes updates here. Do not edit `content/docs-*` files directly — they will be overwritten on the next sync.
35+
36+
Manually-maintained content:
37+
- `content/docs/module.md` — docs landing page
38+
- `content/getting-started/module.md` — getting started tutorial
39+
- All other `content/*/module.md` — blog articles
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# Deploying a Hype Blog with Docker
2+
3+
<details>
4+
slug: deploying-with-docker
5+
published: 03/15/2026
6+
author: Cory LaNou
7+
seo_description: Deploy a Hype-powered blog site with Docker. Covers Dockerfile setup, Dokploy, Heroku, and generic VPS deployment with Docker Compose.
8+
tags: tutorial, docker, deployment, blog, hype
9+
</details>
10+
11+
Hype builds and serves your blog in a single binary. That makes it a natural fit for Docker — one container that builds your site from source and serves it, with no external web server required.
12+
13+
This is exactly how [hypemd.dev](https://hypemd.dev) runs in production. Here's how to do it.
14+
15+
## The Dockerfile
16+
17+
A Hype blog needs two things at deploy time: the `hype` binary and your site content. A two-stage Docker build keeps the image lean:
18+
19+
```dockerfile
20+
FROM golang:1.25 AS builder
21+
RUN go install github.com/gopherguides/hype/cmd/hype@latest
22+
23+
FROM golang:1.25
24+
COPY --from=builder /go/bin/hype /usr/local/bin/hype
25+
WORKDIR /site
26+
COPY . .
27+
RUN hype blog build
28+
EXPOSE 3000
29+
CMD ["hype", "blog", "serve", "--addr", ":3000"]
30+
```
31+
32+
What this does:
33+
34+
1. **Builder stage** — installs `hype` from source using Go 1.25 (hype's minimum version)
35+
2. **Runtime stage** — copies the built binary, copies your site content, runs `hype blog build` to generate the static site, then serves it on port 3000
36+
37+
The `hype blog build` step executes all your code blocks, resolves includes, and generates `public/`. The `hype blog serve` command serves that directory with live reload in development, or you can add the `--production` flag for production-grade serving with compression and security headers.
38+
39+
## Production Serving
40+
41+
As of the latest release, `hype blog serve` supports a `--production` flag that enables embedded Caddy for production-grade serving:
42+
43+
```dockerfile
44+
CMD ["hype", "blog", "serve", "--addr", ":3000", "--production"]
45+
```
46+
47+
This gives you:
48+
49+
- **Compression** — gzip and zstd with automatic content negotiation
50+
- **Security headers** — X-Content-Type-Options, X-Frame-Options, Referrer-Policy
51+
- **Cache control** — 1-year immutable caching for static assets, 1-hour for HTML
52+
- **Clean URLs** — automatic index.html resolution
53+
- **Custom 404** — auto-detected from `public/404.html` if present
54+
55+
No nginx or Caddy sidecar needed. It's all in the binary.
56+
57+
## Deploying with Dokploy
58+
59+
[Dokploy](https://dokploy.com) is a self-hosted PaaS that makes Docker deployments simple. This is what hypemd.dev uses.
60+
61+
### Setup
62+
63+
1. Create a new application in Dokploy and link your GitHub repo
64+
2. Set the build type to **Dockerfile** (not Nixpacks — Dokploy defaults to Nixpacks which won't know how to build a Hype site)
65+
3. Deploy
66+
67+
### Domain Configuration
68+
69+
In Dokploy's domain settings:
70+
71+
- **Host**: your domain (e.g., `hypemd.dev`)
72+
- **Container Port**: `3000`
73+
- **HTTPS**: enable with Let's Encrypt for automatic TLS
74+
75+
Point your DNS A record to your Dokploy server's IP address.
76+
77+
### Auto-Deploy
78+
79+
Enable autodeploy in Dokploy's Git settings. Every push to main triggers a rebuild and redeploy. Combined with the [docs sync workflow](/single-source-docs/) pattern, this means documentation changes in your source repo automatically propagate to your live site.
80+
81+
## Deploying with Heroku
82+
83+
Heroku's container stack works with the same Dockerfile, with one adjustment — Heroku assigns a dynamic port via the `$PORT` environment variable.
84+
85+
### heroku.yml
86+
87+
Create a `heroku.yml` at the repo root:
88+
89+
```yaml
90+
build:
91+
docker:
92+
web: Dockerfile
93+
```
94+
95+
### Dynamic Port
96+
97+
Modify the CMD to use Heroku's port:
98+
99+
```dockerfile
100+
CMD hype blog serve --addr ":$PORT" --production
101+
```
102+
103+
Note the shell form (no brackets) so `$PORT` gets expanded.
104+
105+
### Deploy
106+
107+
```bash
108+
heroku stack:set container
109+
git push heroku main
110+
```
111+
112+
## Generic Docker / VPS Deployment
113+
114+
For any server with Docker installed:
115+
116+
### Build and Run
117+
118+
```bash
119+
docker build -t my-blog .
120+
docker run -d -p 3000:3000 --name my-blog my-blog
121+
```
122+
123+
Your site is now serving on port 3000.
124+
125+
### Docker Compose
126+
127+
For a more complete setup with automatic restarts:
128+
129+
```yaml
130+
services:
131+
blog:
132+
build: .
133+
ports:
134+
- "3000:3000"
135+
restart: unless-stopped
136+
```
137+
138+
```bash
139+
docker compose up -d
140+
```
141+
142+
### TLS with a Reverse Proxy
143+
144+
If you're not using `--production` mode or need TLS termination, put a reverse proxy in front:
145+
146+
```yaml
147+
services:
148+
blog:
149+
build: .
150+
restart: unless-stopped
151+
152+
caddy:
153+
image: caddy:2
154+
ports:
155+
- "80:80"
156+
- "443:443"
157+
volumes:
158+
- ./Caddyfile:/etc/caddy/Caddyfile
159+
- caddy_data:/data
160+
restart: unless-stopped
161+
162+
volumes:
163+
caddy_data:
164+
```
165+
166+
With a `Caddyfile`:
167+
168+
```
169+
yourdomain.com {
170+
reverse_proxy blog:3000
171+
}
172+
```
173+
174+
Caddy handles TLS automatically via Let's Encrypt.
175+
176+
## Content Updates
177+
178+
The deployment workflow is simple:
179+
180+
1. Push content changes to your repo
181+
2. Your platform rebuilds the Docker image
182+
3. `hype blog build` runs inside the container, executing all code blocks fresh
183+
4. The new container starts serving
184+
185+
Every deploy is a clean build. Your code examples are re-executed, includes are re-resolved, and broken references fail the build before they reach production.
186+
187+
## Key Takeaways
188+
189+
- **Single binary** — `hype` builds and serves, no external dependencies
190+
- **Docker-native** — simple two-stage Dockerfile works everywhere
191+
- **Production-ready** — `--production` flag adds compression, security headers, and caching
192+
- **Git-driven** — push to deploy, content is always current
193+
- **Build-time validation** — broken code or missing files fail the build, not the reader

0 commit comments

Comments
 (0)