What We Are Doing
If you are somewhere that blocks VPNs through deep packet inspection (DPI), SNI filtering, or crude port blocking, the goal is to make your VPN traffic look as boring as possible.
The quick win is to put it on port 443, the same port used by HTTPS. That is the lifeline of the modern web, so most firewalls are reluctant to block it.
But think of it as changing your outfit but not your walk: just putting Shadowsocks (which Outline runs under the hood) on port 443 does not make it indistinguishable from real HTTPS. To a modern DPI system, it still has a unique fingerprint. If you want to disappear in plain sight, you need to wrap it in actual TLS or another disguise layer.
Why Port 443 Matters and Its Limits
Port 443 is the default for encrypted web traffic. Blocking it would break Gmail, YouTube, Facebook, banking apps, and much more.
Using 443 for your VPN helps against simple port-based blocks. It does not stop advanced DPI, which can still detect Shadowsocks’ handshake patterns even inside encryption.
Think of it as changing your outfit but not your walk. Observers may not see your face, but they still recognize the way you move.
How Outline Works
Outline is a friendly manager and server wrapper for Shadowsocks. It runs a SOCKS5 proxy with strong AEAD encryption and offers an API for generating and revoking access keys.
It does not speak TLS natively. To mimic HTTPS convincingly, you must add a plugin or a front-end reverse proxy that handles TLS and passes traffic inside a valid protocol like WebSocket.
1. Provision Your Server
Choose a VPS provider that is not hostile to privacy. Good options include Hetzner, DigitalOcean, and Vultr. The Oracle free tier works if you enjoy tinkering, but it can be unreliable.
Stick to Ubuntu 20.04 or 22.04 for compatibility.
Open only these inbound ports for now:
1443/tcp # VPN traffic disguised as HTTPS
253/udp # DNS (for fallback only, see DNS notes below)2. Install Outline Server
Run the official installer:
1curl -sS https://getoutline.org/install.sh | sudo bashThis will:
- Install Docker if needed
- Set up the Outline Manager service
- Give you an API URL and fingerprint for connecting
Manage the server using the Outline Manager desktop app.
3. Put It on Port 443
By default, Outline listens on a high random port. To change it to 443, you need to modify the Docker Compose configuration directly, as editing access.txt won’t change the listening port of the Shadowsocks server managed by Outline. The access.txt file is for access keys, not server configuration.
Edit the Docker Compose mapping to expose port 443 and ensure the Outline service inside the container listens on port 443.
First, access your server via SSH and open the docker-compose.yml file:
1sudo nano /opt/outline/docker-compose.ymlLocate the ports section for the shadowsocks service and ensure it maps the external port 443 to the internal container port 443. It might look something like this initially, with a high random port:
1ports:
2 - "8080:8080" # Example, your random port will be differentChange it to:
1ports:
2 - "443:443"Additionally, you might need to ensure the Shadowsocks configuration within the Docker container is also set to listen on port 443. While Outline typically handles this when it sets up the service, if you encounter issues, you may need to check Outline’s internal configuration files (though this is less common for simple port changes). For most setups, just changing the docker-compose.yml ports mapping is sufficient.
Restart:
1docker-compose -f /opt/outline/docker-compose.yml down
2docker-compose -f /opt/outline/docker-compose.yml up -dThis gets you the “minimal camouflage” setup. It helps against basic censorship but still looks like Shadowsocks to advanced DPI.
4. HTTPS (Recommended)
Running Outline over HTTPS significantly enhances security and can help bypass certain network restrictions. This involves setting up a reverse proxy (like Nginx) to handle SSL/TLS encryption and forward traffic to your Outline server.
First, ensure you have a domain name (e.g., vpn.example.com) pointed to your server’s IP address.
Install Nginx and Certbot
1sudo apt update
2sudo apt install nginx certbot python3-certbot-nginx -yObtain an SSL/TLS Certificate
Use Certbot to get a free SSL/TLS certificate from Let’s Encrypt for your domain. Replace vpn.example.com with your actual domain.
1sudo certbot --nginx -d vpn.example.comFollow the prompts. Certbot will automatically configure Nginx to use the certificate and set up automatic renewals.
Configure Nginx as a Reverse Proxy
Create a new Nginx configuration file for your domain:
1sudo nano /etc/nginx/sites-available/vpn.example.comAdd the following configuration. This assumes your Outline server is listening on localhost:443 (as configured in the previous step). If you changed Outline’s port, adjust proxy_pass accordingly.
1server {
2 listen 80;
3 server_name vpn.example.com;
4 return 301 https://$host$request_uri;
5}
6
7server {
8 listen 443 ssl;
9 server_name vpn.example.com;
10
11 ssl_certificate /etc/letsencrypt/live/vpn.example.com/fullchain.pem;
12 ssl_certificate_key /etc/letsencrypt/live/vpn.example.com/privkey.pem;
13 ssl_protocols TLSv1.2 TLSv1.3;
14 ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
15 ssl_prefer_server_ciphers off;
16
17 location / {
18 proxy_pass http://127.0.0.1:443; # Or your Outline's listening address and port
19 proxy_set_header Host $host;
20 proxy_set_header X-Real-IP $remote_addr;
21 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
22 proxy_set_header X-Forwarded-Proto $scheme;
23 proxy_buffering off;
24 proxy_max_temp_file_size 0;
25 }
26}Enable the Nginx Configuration
Create a symbolic link to enable the new configuration and then test Nginx syntax and restart.
1sudo ln -s /etc/nginx/sites-available/vpn.example.com /etc/nginx/sites-enabled/
2sudo nginx -t
3sudo systemctl restart nginxWith this setup, Nginx handles the HTTPS connection, decrypts the traffic, and forwards it to your Outline server, which can now listen on its internal port (e.g., 443) without directly managing SSL/TLS certificates.
5. Cloudflare Routing
Cloudflare does not proxy raw TCP over 443 unless you pay for Spectrum. The free plan works for HTTP, HTTPS, and WebSocket. Therefore, to route your Outline VPN traffic through Cloudflare’s free tier, your Outline client must use a WebSocket plugin.
Configure your Nginx (as described in the HTTPS section) to proxy WebSocket traffic to your Outline Shadowsocks server. This involves adding a location block in your Nginx configuration to handle a specific WebSocket path (e.g., /your_websocket_path) and proxy it to your Outline server’s internal address and port.
On the client side, ensure your Shadowsocks client is configured to use a WebSocket plugin (like v2ray-plugin) and the specified WebSocket path. For example, with Shadowsocks-Rust, your client configuration might look like this:
1{
2 "server": "your_domain.com",
3 "server_port": 443,
4 "password": "your_password",
5 "method": "chacha20-ietf-poly1305",
6 "plugin": "v2ray-plugin",
7 "plugin_opts": "tls;host=your_domain.com;path=/your_websocket_path"
8}This setup makes your VPN traffic appear as regular web traffic to Cloudflare, further enhancing obfuscation and bypassing advanced deep packet inspection (DPI).
6. Connect Your Client
Download the Outline client for your platform:
Paste in your access key from the Outline Manager.
If you switch from raw IP to a domain for TLS, you must regenerate or edit the key to match the new hostname.
7. Test Your Stealth
Testing is more than “it connects”. Use these:
- gfw.report to check if the handshake is blocked in censorship regions
- Wireshark or mitmproxy to inspect packet patterns
Minimal camouflage will still show a Shadowsocks signature. Strong camouflage should be indistinguishable from normal HTTPS.
DNS warning: Many censorship regimes hijack or block UDP 53. For better stealth, configure DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT) on your device or in the Outline client.
Active Probing Defense
In some places, censors will connect to your IP on 443 and try to speak Shadowsocks. If your server replies, they blacklist you.
Plugins like Cloak or nginx fronting can drop these connections unless they match a known pattern.
Summary
- Port 443 is a good first step, but on its own it only beats basic port blocking.
- For serious stealth, add a TLS or WebSocket transport with a valid certificate.
- Cloudflare routing only works if traffic is inside HTTP or WebSocket.
- Protect against active probing in high-risk environments.
References and Further Reading
If you only need to get around crude blocks, changing Outline to port 443 might be enough. If you are under active, sophisticated censorship, you will need to dress it up in TLS and maybe hide it behind something bigger like Cloudflare. I will try this idea and write another blog detailing the journey.
The more it looks and acts like normal HTTPS, the longer it will survive.