Skip to content

Setup

Spin up a VPS with Ubuntu 24.04.3 LTS and run the following commands:

Find/Replace eth0IP with your VPS public IP address

apt-get update
apt-get upgrade
apt-get install nginx libnginx-mod-stream ssl-cert ca-certificates curl iptables-persistent iptables

hostnamectl set-hostname localhost
make-ssl-cert generate-default-snakeoil --force-overwrite

cat > /etc/nginx/nginx.conf < 'EOF'
user root;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;

load_module /usr/lib/nginx/modules/ngx_stream_module.so;

events {
    worker_connections 1024;
}

stream {
    upstream ssh {
        server 127.0.0.1:22;
    }

    upstream web {
        server 127.0.0.1:8443;
    }

    map $ssl_preread_protocol $upstream {
        "" ssh;
        default web;
    }

    server {
        listen 443;
        proxy_pass $upstream;
        ssl_preread on;
    }
}

http {
    # Define upgrade connection map for WebSocket
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    # HTTPS server
    server {
        listen 127.0.0.1:8443 ssl http2;
        server_name _;

        access_log /var/log/nginx/access_ssl.log;
        error_log /var/log/nginx/error_ssl.log;

        # SSL certificate (add missing semicolons)
        ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
        ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

        # SSL security settings
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 10m;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers on;

        # Serve default nginx page for root and other paths
        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
        }

        # Proxy configuration for the specific route
        location /aa5024b363d7f93ec2f56b0402390ee9/ {
            # Proxy to local service on host machine via Docker gateway
            proxy_pass http://127.0.0.1:8080/;

            # Standard proxy headers
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # WebSocket support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            # Timeout settings for long-lived connections
            proxy_connect_timeout 7d;
            proxy_send_timeout 7d;
            proxy_read_timeout 7d;
        }
    }
}
EOF

cat > /etc/systemd/system/fishler.service << 'EOF'
[Unit]
Description=fishler
ConditionPathExists=/opt/honey/fishler
After=network.target uplink.target

[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE
Type=simple
User=root
LimitNOFILE=1024

Restart=on-failure
RestartSec=10

WorkingDirectory=/opt/honey/
ExecStart=/opt/honey/fishler --uplink-server-address 127.0.0.1:50051 serve --any-account --banner 'SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.14' --ip <eth0IP> --port 22

# Log errors and stdout to the journal
PermissionsStartOnly=true
StandardOutput=journal
StandardError=journal
SyslogIdentifier=fishler

[Install]
WantedBy=multi-user.target
EOF

cat > /etc/systemd/system/uplink.service << 'EOF'
[Unit]
Description=uplink
ConditionPathExists=/opt/honey/uplink
After=network.target

[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE
Type=simple
User=root
LimitNOFILE=1024

Restart=on-failure
RestartSec=10

WorkingDirectory=/opt/honey/
ExecStart=/opt/honey/uplink

# Log errors and stdout to the journal
PermissionsStartOnly=true
StandardOutput=journal
StandardError=journal
SyslogIdentifier=uplink

[Install]
WantedBy=multi-user.target
EOF

cat > /etc/iptables/rules.v4 << 'EOF'
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]

# Logs
-N LOG_DROP
-A LOG_DROP -j LOG --log-level 6 --log-prefix "IPTABLES:DROP: "
-A LOG_DROP -j DROP


# Acceptable UDP traffic

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 443 -j ACCEPT
-A TCP -p tcp --dport 80 -j ACCEPT

# Acceptable ICMP traffic

# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Boilerplate acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i DOCKER -j ACCEPT

# Pass traffic to protocol-specific chains
## Only allow new connections (established and related should already be handled)
## For TCP, additionally only allow new SYN packets since that is the only valid
## method for establishing a new TCP connection
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

# Reject anything that's fallen through to this point
## Try to be protocol-specific w/ rejection message
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable

# Output Rules
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o DOCKER -j ACCEPT
-A OUTPUT -p tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp --dport 22 -j ACCEPT
-A OUTPUT -p udp --dport 53 -j ACCEPT
-A OUTPUT -o eth0 -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT

-A INPUT -j LOG_DROP
-A FORWARD -j LOG_DROP
-A OUTPUT -j LOG_DROP
-A UDP -j LOG_DROP
-A TCP -j LOG_DROP
-A ICMP -j LOG_DROP

# Commit the changes
COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
EOF

cat > /etc/iptables/rules.v6 << 'EOF'
*filter
# Allow all outgoing, but drop incoming and forwarding packets by default
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]

# Logs
-N LOG_DROP
-A LOG_DROP -j LOG --log-level 6 --log-prefix "IPTABLES:DROP: "
-A LOG_DROP -j DROP

-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT -s fe80::0000:0000:0000:0000/16 -j ACCEPT
-A INPUT -d fe80::0000:0000:0000:0000/16 -j ACCEPT

-A INPUT -j LOG_DROP
-A FORWARD -j LOG_DROP
# Meh...
-A OUTPUT -j ACCEPT
-A UDP -j LOG_DROP
-A TCP -j LOG_DROP
-A ICMP -j LOG_DROP

# Commit the changes
COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
EOF

cat > /etc/ssh/sshd_config << 'EOF'
Include /etc/ssh/sshd_config.d/*.conf
Port 22
ListenAddress 127.0.0.1
PermitRootLogin yes
PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem   sftp    /usr/lib/openssh/sftp-server
EOF

apt remove -yq $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)

install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

apt update
apt install -yq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

systemctl daemon-reload

service docker start
service uplink start
service fishler start
service nginx start

systemctl enable docker
systemctl enable uplink
systemctl enable fishler
systemctl enable nginx

reboot now