shadowsocks-c swapped its event loop and kept every old name
Self-contained Shadowsocks implementation in C with libuv, asynchronous DNS, and portable static builds for Linux, macOS, Windows, and FreeBSD.
At a glance
- What is it?
- shadowsocks-c is a pure C implementation of the Shadowsocks proxy aimed at embedded devices and low-end boxes, and its recent history explains most of its oddities. After years of bug fixes only, it was modernised in September 2026: pinned sources were bundled in, the event loop moved from libev to libuv, Windows and macOS backends were added, and the project was renamed while keeping its previous name as a compatibility alias.
- Who is it for?
- shadowsocks-c fits an embedded target or a low-end box where a full runtime is too heavy, and a builder who wants a proxy that compiles from a checkout without fetching anything. It does not fit a team that wants an actively developed proxy with a short feature cycle, because development was pointed elsewhere for years and only resumed in 2026.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- shadowsocks/shadowsocks-c16,186 ★ · +10
| Repository | 2026-09-21 | 2026-11-13 |
|---|---|---|
| shadowsocks/shadowsocks-c | 16.2k | 16.2k |
10 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A bug-fix-only phase, then a rewrite of the event loop in one month
The project history section is the most informative part of this readme, because it explains the code you are looking at. The repository began as shadowsocks-libev, a lightweight C implementation built around the libev event loop, and after a period it entered a bug-fix-only maintenance phase with new development directed at the Rust implementation. Then, in September 2026, two changes happened in sequence and both are linked. The build modernisation bundled pinned dependency sources into the repository, removed several external dependencies and added static-build validation across platforms. The migration that followed replaced libev with libuv, added Windows completion-port and macOS kqueue support, expanded asynchronous runtime DNS coverage, and tightened the lint checks in continuous integration. So the current code is a few months old on top of the earlier shadowsocks-libev codebase, and that combination is what you are adopting.
The rename kept the old name as an alias everywhere
The project and its repository were renamed to reflect that it is a pure C implementation, and the readme then spends a section on what deliberately did not change. Commands such as the local and server binaries keep their names, the public header keeps its name, and the embedding library's binary interface stays compatible. New builds ship a library and a CMake package under the new name, while legacy library filenames and the old package lookup name remain available as compatibility aliases. Configuration paths, distribution package names and service names are retained too, which is why the installation examples further down still refer to the previous name. The repository also keeps the old commit history and releases. If you are reading the readme looking for a migration guide, this is it, and the answer is that there is nothing to migrate, because the old name is still the name your packaging scripts and service units use.
The recommended way to run a server is a locked-down container
Docker is called the recommended way to run a server, and the command shown is more interesting than the image name. The image contains bundled, fully static binaries and supports Linux on both AMD64 and ARM64, including containers under Docker Desktop on macOS and Windows. The configuration it reads is a small JSON document holding a listen address, a port, a password, a cipher and a mode:
{
"server": "0.0.0.0",
"server_port": 8388,
"password": "replace-with-a-long-random-password",
"method": "aes-256-gcm",
"mode": "tcp_and_udp"
}The container is then started detached with a restart policy, as your own user and group id, with a read-only root filesystem, every Linux capability dropped, the no-new-privileges option set, both protocol ports published, and the configuration bind-mounted read-only:
docker pull ghcr.io/shadowsocks/shadowsocks-c:latest
docker run -d --name shadowsocks-c --restart unless-stopped \
--user "$(id -u):$(id -g)" --read-only --cap-drop=ALL \
--security-opt=no-new-privileges:true \
-p 8388:8388/tcp -p 8388:8388/udp \
--mount type=bind,src="$PWD/config.json",dst=/etc/shadowsocks-c/config.json,readonly \
ghcr.io/shadowsocks/shadowsocks-c:latestPublishing both the TCP and the UDP port is not decoration, because the sample configuration selects a mode that handles both. The stated reason for running as your own user id is that the container has to read a configuration file you own, which is the kind of detail that saves an afternoon of debugging a permission error.
Building from source needs no network, no submodules and no packages
The build section is the strongest argument for the modernisation, and the constraint is explicit. The default build uses pinned sources included in the repository, and configuration and compilation need nothing else: no Git submodules, no dependency packages to install, and no network access at all. What you do need is a C11 compiler, CMake 3.20 or newer, and either Make or Ninja. Python is used by the tests, and building documentation is optional and needs Doxygen 1.9.4 or newer. The four commands are configure, build, run a labelled subset of the tests, and install to a prefix of your choosing:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
ctest --test-dir build -L 'unit|vendor' --output-on-failure
cmake --install build --prefix /your/install/prefixA submodules file still exists at the root even though submodules are no longer part of the default path, which is worth knowing if you read the tree to work out what a build will fetch.
The documentation is generated from the source and published on merge
The command line reference and the configuration guide are generated with Doxygen from the source and published after updates to the default branch. The readme tells you to use the help flag for grouped options and the version flag for version information, and points at a page on command line conventions for the long flags, the short aliases and, importantly, the precedence between configuration sources. Two further documents are named for decisions rather than features: one on modernisation, covering build options and platform support, and one on performance, described as measured tradeoffs. There is also a wiki page comparing features across the different implementations, which is the place to answer what this one does not do.
Six years between two tags, and the newest one predates the rewrite
The release history is short enough to read at a glance and it explains the cadence. The current version is 3.3.6, published in February 2026. The tag before it is 3.3.5 from September 2020, and before that 3.3.4 from January 2020, so there is a gap of more than five years between the two most recent releases. That is the bug-fix-only phase described in the history section, and it means the version number has not tracked the amount of change in the code, since the libuv migration and the static-build work happened after 3.3.6 was cut, on a branch that produced no new tag. The default branch was last pushed on 2026-10-28. If you need a pinned, identifiable build, the container tags give you a way to get one, because a moving tag follows the branch while version tags and commit-addressed tags identify a single published build.
Packaging is per distribution, and one channel kept the old name
The installation section is a list of distribution recipes rather than one supported path, and the readme is candid about which is preferred. There are guides for Debian and Ubuntu with a repository route that is marked as not recommended and a route that builds a package from source, guides for Fedora and RHEL, Arch and Manjaro, NixOS, a plain Nix route, a direct build for Unix-like systems, FreeBSD with separate install, configuration and client notes, OpenWRT, macOS, Windows through MinGW, and Docker. Underneath sit the packaging directories that match: a Debian tree whose changelog is the project's changelog, an RPM tree, a Snap directory, a Copr configuration, shell completions, and a scripts directory. The one warning to keep is that existing Snap packages still use the previous name and may predate the modernisation, so a Snap install and a source build are not currently the same thing. The licence is GPL 3.0, and the readme names the original author and the two maintainers.
Editorial conclusion
shadowsocks-c fits an embedded target or a low-end box where a full runtime is too heavy, and a builder who wants a proxy that compiles from a checkout without fetching anything. It does not fit a team that wants an actively developed proxy with a short feature cycle, because development was pointed elsewhere for years and only resumed in 2026. Before you deploy it, read the compatibility notes rather than the project name, since commands, the public header, the library interface, configuration paths and distribution package names all survive from the previous name and several packaging routes are still described under it. Check which image tag you pull as well, because the recommended container runs with a read-only root filesystem, no Linux capabilities and no new privileges, and the reference documentation is generated from the source rather than written by hand.
Frequently asked questions
Is Shadowsocks safe to use?
On the server side the documented sample configuration pairs a long random password with an authenticated cipher, and the recommended container is run with a read-only root filesystem, all Linux capabilities dropped, no new privileges, as your own user id, and the configuration file mounted read-only.
Can Shadowsocks be detected?
The README's opening sections and quick start do not discuss detection. What it documents is the implementation and its configuration surface, including the protocol mode that handles both TCP and UDP and the bundled static binaries, plus a wiki page comparing features across the different implementations of the protocol, which is where such a comparison belongs.
How do I run a shadowsocks-c server with Docker?
Write a configuration file with your own long random password, a port, an authenticated cipher such as aes-256-gcm and a mode handling both protocols, then run the published image with the container detached, restarting unless stopped, as your own user and group id, with a read-only root filesystem, all capabilities dropped and the no-new-privileges option set, publishing both ports and bind-mounting the configuration file read-only. Logs come from the container logs and the container is stopped with a normal stop command.
How do I build shadowsocks-c from source?
You need a C11 compiler, CMake 3.20 or newer, and Make or Ninja. The repository bundles pinned dependency sources, so configuration and compilation need no submodules, no installed dependency packages and no network access. Configure with CMake into a build directory, build in parallel, run the tests filtered by label, and install to a prefix of your choosing.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shadowsocks-shadowsocks-c)Star history chart for your README
[](https://hysenlabs.com/projects/shadowsocks-shadowsocks-c)Was this useful?