Like most people, when I started using Clash/Mihomo, I opted for graphical clients based on the core for the sake of convenience. Essentially, these Mihomo clients are very similar: they all use the same backend, with the primary purpose of offering a GUI, managing config files, handling subscription updates, and system proxy settings. With this in mind, I think the usefulness of a Mihomo client largely depends on how well it implements config overrides. Every configuration file obtained or subscribed to through a client goes through various override steps—such as changing the mixed-port
, adding sniffer
settings, and so on—before it’s handed over to the Mihomo core for startup.
However, not all clients do this basic job adequately. Take ShellCrash, for example—the override mechanism is frequently buggy and feels more like an afterthought. If the client can’t even reliably update and tweak config files, it hardly deserves to be called a decent client.
Instead of depending on these unreliable, black-box Mihomo clients, why not just take direct control? Manage your own configuration files and start the core yourself. This way, you get a cleaner, more reliable, and fully transparent setup.
What You Need to Know
- Basic Linux skills
- Familiarity with CLI editors, like
nano
- Have a Substore instance set up (optional)
Installing the Mihomo Core
On Debian-based systems, you can install precompiled .deb
packages. For other systemd
-enabled distributions, just download the compiled binary, rename it to mihomo
, and place it in /usr/local/bin
:
|
|
Next, create /etc/systemd/system/mihomo.service
:
|
|
Run systemctl daemon-reload
to refresh systemd
. Since there’s no config file yet, you can’t actually start the core, but you can enable it to start on boot using systemctl enable mihomo
—ready for when your config is set up.
Configuration Files
When starting, the core reads /etc/mihomo/config.yaml
. With the black-box clients out of the picture, you’re free to customise your config files however you like. Some VPN/proxy providers supply a complete config file you can download with curl
.
For subscription management, I’m currently using Substore. I’ve previously shared a Quickstart Guide to Substore Subscription Management if you want to refer to that for custom subscription workflows. To support a pure-core setup, my Substore custom override script now includes a full
parameter, generating a standalone config file with all necessary ports, unified delay, external-controller settings, and more—ready to use out of the box.
Once you’ve set up Substore, just download your config file and start the core:
|
|
Custom Override Rules
If my example config doesn’t work for your needs, that’s no problem—just tweak or add any overrides you like.
Over the years, I’ve tested various override rules, sometimes even writing my own from scratch. Even with that, there are always edge cases—private domains for stuff like SSH on non-standard ports, for instance—that you won’t want to publish on GitHub. In those cases, you’ll want to append your own private overrides on top.
The good thing is that Substore supports chaining multiple override scripts. All you need to do is add your custom script during config generation.
|
|
Note: When overriding rules, always use .unshift()
to add to the top of the list—don’t use .push()
to add at the end, or they’ll never match (since anything after MATCH
is ignored).
Building Your Own Config From Scratch
Don’t like my override rules, or prefer not to use Substore at all? No problem! Just refer to the Mihomo Docs and build your own config from the ground up:
|
|
Control Panel / Dashboard
Choose whichever dashboard you like. For example, I ran into some odd issues with Mihomo’s built-in external-ui
. So, I just deploy a separate Docker web dashboard—after all, it’s just a simple web UI. Just make sure your core’s API uses HTTP, and set your web panel to use HTTP as well (if you try HTTPS, you’ll be blocked by CORS policy).
|
|
compose.yml
example:
|
|
Automatic Maintenance
With the core running, how do you handle auto-updates for your subscription configs?
Simple—write a shell script and automate it with cron. For instance, if you want to update your config and restart Mihomo at 3am daily, create /etc/mihomo/auto_update.sh
:
|
|
Use crontab -e
to edit your crontab and schedule auto-updates at 3am daily:
|
|
Firewall Configuration
Manually setting up firewall rules to direct traffic through the Mihomo core isn’t as tricky as it sounds. I’ve previously covered the details in my article “From Beginner to Advanced: Tailscale + ShellCrash for Remote Networking and Bypassing Internet Censorship”. Here, I’ll just summarise the practical steps.
For my setup, I want all traffic from the tailscale0
interface to be transparently proxied by Mihomo. If all you need is TCP interception, iptables
REDIRECT is sufficient; but for UDP, QUIC, etc., you’ll need TPROXY. Don’t forget IPv6!
Here’s my firewall config:
|
|
Most modern distributions do not persist firewall rules by default. For details about rule persistence, see the “Routing Rule Persistence” and “iptables Rule Persistence” sections referenced in my Tailscale article.
How Do I Configure Local Proxying?
Most proxy clients, such as the default for ShellCrash, use REDIRECT as standard, which is usually sufficient for most use cases. Example for REDIRECT:
|
|
Here, 7892 should match the redir-port
in your Mihomo config, and eth0
is the interface you want to intercept. Compared to TPROXY, this is remarkably straightforward.
Personally, I dislike forcing all local traffic through the firewall proxy route. Instead, I prefer to use environment variables, proxychains
, or per-application proxy settings as needed to route traffic through Mihomo. For example, if you want Docker to use the proxy, you only need to edit Docker’s /etc/docker/daemon.json
and specify the proxy endpoints, rather than intercepting all network traffic at the interface level:
|
|
Why Go to All This Trouble? Isn’t Using a GUI Client Easier?
Don’t ask. Some of us just prefer living in the terminal void.