Decided to start a new category "Celestial Book", with the url-slug "huangshigong"
Used to store tutorial content entirely generated by AI
This is the first one
Containerized Deployment of Mihomo Proxy Without Docker Hub
Applicable Scenarios
The server has almost no external network access, Docker Hub is unavailable (or cannot pull any images). Podman, BaoTa Panel, or directly installed Docker Engine are all applicable.
Core Idea
- Use any existing Alpine image on the server (e.g.,
redis:alpine) as the CA certificate source during build, and base the final image onscratch, without pulling any additional images. - Place all new files under the
/root/mihomo/directory, without polluting other locations on the server. - Only the target container uses the proxy; the host machine and other containers are unaffected.
Step 1: Prepare Files
The following files can be downloaded on your personal PC (with normal access to GitHub) and then placed in the /root/mihomo/ directory on the server.
| File | Purpose | How to Get |
|---|---|---|
mihomo (binary) | Proxy core | Download mihomo-linux-amd64-v*.gz from GitHub Releases, extract and rename to mihomo |
geoip.metadb | GeoIP database | Download geoip.metadb from meta-rules-dat Releases, place in data/ subdirectory |
config.yaml | Proxy configuration | See below |
Dockerfile | Image build | See below |
docker-compose.yml | Container orchestration | See below |
Final directory structure:
/root/mihomo/
├── mihomo # Binary file
├── config.yaml # Proxy configuration
├── Dockerfile
├── docker-compose.yml
└── data/
└── geoip.metadb # GeoIP database
Step 2: config.yaml
Core idea: The subscription URL returns a full configuration. Extract the DNS and rules sections directly into config.yaml; proxy nodes are pointed to the subscription URL via proxy-providers, and mihomo automatically pulls updates daily.
Some parts depend on the provider. Fill in the corresponding fixed parts from the subscription URL given by the provider. Can be done by AI.
url:Fill in your subscription address. The URL itself includes authentication (a random token in the path), no extra authentication is needed.
# Ports and Mode
port: 7890
socks-port: 7891
allow-lan: true
mode: Rule
log-level: info
external-controller: 0.0.0.0:9090
# DNS (extracted from subscription return content)
dns:
enable: true
# ... Fill in the complete content after pulling from subscription URL
# Automatically pull the latest nodes from subscription address daily
proxy-providers:
sub:
type: http
url: "https://your-subscription-url?clash=3"
interval: 86400
path: ./providers/sub.yaml
health-check:
enable: true
url: https://cp.cloudflare.com
interval: 300
# Auto-select the fastest node
proxy-groups:
- name: 🔰 Select Node
type: url-test
use: [sub]
url: https://www.gstatic.com/generate_204
interval: 300
# Rules (extracted from subscription return content)
rules:
- GEOIP,CN,DIRECT
- MATCH,🔰 Select Node
Step 3: Dockerfile
FROM redis:alpine AS certs
FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY mihomo /mihomo
ENTRYPOINT ["/mihomo"]
CMD ["-d", "/etc/mihomo"]
- First stage:
FROM redis:alpineuses an existing image on the server, only to extract the CA root certificate. - Second stage:
FROM scratchis an empty image. The final artifact only contains the mihomo binary and CA certificate, clean and lean. redis:alpineis only referenced as a build artifact; it is not run or modified. It can be replaced with any Alpine-based image available on the server.
Step 4: docker-compose.yml
services:
mihomo:
build: .
container_name: mihomo
restart: unless-stopped
volumes:
- ./config.yaml:/etc/mihomo/config.yaml:ro
- ./data:/etc/mihomo
ports:
- "7890:7890"
- "9090:9090"
build: .uses the local Dockerfile to build, no need to pull external images.- Port
9090is for the REST API (optional, for hot-reload or status queries).
Step 5: Build and Start
cd /root/mihomo
# Ensure the binary file exists and is executable
chmod +x mihomo
# Build and start
docker compose build
docker compose up -d
Verify the proxy is working:
curl -x http://localhost:7890 https://www.google.com -o /dev/null -w "%{http_code}"
A return of 200 indicates success.
Step 6: Make Other Containers Use the Proxy
Taking the blog backend container as an example, add environment variables to its docker-compose.yml:
environment:
HTTP_PROXY: "http://172.17.0.1:7890"
HTTPS_PROXY: "http://172.17.0.1:7890"
NO_PROXY: "localhost,127.0.0.1"
172.17.0.1 is the default Docker bridge gateway. Containers use it to access port 7890 mapped from the host's mihomo. If the backend uses a custom network, use docker inspect <container_name> | grep Gateway to confirm the actual gateway address.
After rebuilding the target container, verify inside the container:
docker exec <container_name> curl -x http://172.17.0.1:7890 https://www.google.com -o /dev/null -w "%{http_code}"
A return of 200 means it's done.