{"id":1441,"date":"2026-03-18T18:55:57","date_gmt":"2026-03-18T09:55:57","guid":{"rendered":"https:\/\/openclaw.helloai.jp\/?p=1441"},"modified":"2026-03-18T19:47:09","modified_gmt":"2026-03-18T10:47:09","slug":"%e5%9c%a8vps%e4%b8%8a%e9%80%9a%e8%bf%87tailscale%e9%83%a8%e7%bd%b2openclaw%e6%9c%8d%e5%8a%a1%e5%99%a8","status":"publish","type":"post","link":"https:\/\/openclaw.helloai.jp\/?p=1441","title":{"rendered":"\u5728VPS\u4e0a\u901a\u8fc7Tailscale\u90e8\u7f72OpenClaw Web\u670d\u52a1\u5668"},"content":{"rendered":"<h1>Serve Your OpenClaw Workspace on VPS with Tailscale<\/h1>\n<p>As an OpenClaw power user, you&#8217;ve got a workspace full of skills, scripts, blog posts, and projects. But what if you could browse it all from any device, anywhere in the world? In this guide, I&#8217;ll show you how to set up a lightweight HTTP server on your VPS and access it securely through Tailscale.<\/p>\n<h2>Why This Setup Matters<\/h2>\n<p>Your OpenClaw workspace is the heart of your AI-powered workflow. Organizing files is great, but being able to quickly browse drafts, review images, and check scripts from your phone or laptop makes it truly useful. With Docker and Tailscale, we can create a secure, always-accessible workspace server in minutes.<\/p>\n<h2>Prerequisites<\/h2>\n<p>Before we start, make sure you have:<\/p>\n<li>A VPS running Linux (Ubuntu, Debian, etc.)<\/li>\n<li>Docker and Docker Compose installed<\/li>\n<li>Tailscale installed on both your VPS and the device you&#8217;ll browse from<\/li>\n<li>Root or sudo access on your VPS<\/li>\n<h2>Step 1: Organize Your Workspace<\/h2>\n<p>If your workspace is cluttered, take a moment to organize it. A clean structure makes browsing easier:<\/p>\n<pre><code>\n~\/.openclaw\/workspace\/\n\u251c\u2500\u2500 blog\/           # Drafts, published posts, images\n\u251c\u2500\u2500 projects\/       # Standalone projects\n\u251c\u2500\u2500 skills\/         # OpenClaw skills\n\u251c\u2500\u2500 scripts\/        # Python automation scripts\n\u251c\u2500\u2500 tools\/          # Tools and configs\n\u251c\u2500\u2500 memory\/         # Daily notes and memories\n\u2514\u2500\u2500 index.html      # Landing page\n<\/code><\/pre>\n<h2>Step 2: Create a Docker Compose File<\/h2>\n<p>We&#8217;ll use nginx in a Docker container for serving files. Create `docker-compose.workspace-server.yml` in your workspace:<\/p>\n<p>&#8220;`yaml<\/p>\n<p>version: &#8216;3.8&#8217;<\/p>\n<p>services:<\/p>\n<p>workspace-server:<\/p>\n<p>image: nginx:alpine<\/p>\n<p>container_name: openclaw-workspace-server<\/p>\n<p>restart: unless-stopped<\/p>\n<p>ports:<\/p>\n<p>&#8211; &#8220;8000:80&#8221;<\/p>\n<p>volumes:<\/p>\n<p>&#8211; \/root\/.openclaw\/workspace:\/usr\/share\/nginx\/html:ro<\/p>\n<p>&#8211; .\/default.conf:\/etc\/nginx\/conf.d\/default.conf:ro<\/p>\n<pre><code>\n\nThe `:ro` (read-only) flag is important\u2014it ensures the server can't accidentally modify your files.\n\n## Step 3: Configure Nginx\n\nCreate a custom nginx configuration file named `default.conf`:\n\n```nginx\nserver {\n    listen       80;\n    listen  [::]:80;\n    server_name  localhost;\n\n    # Enable directory listing for easier browsing\n    autoindex on;\n    autoindex_exact_size off;\n    autoindex_localtime on;\n\n    # Set proper charset\n    charset utf-8;\n\n    # Serve all files from workspace root\n    location \/ {\n        root   \/usr\/share\/nginx\/html;\n        index  index.html index.htm index.md;\n        try_files $uri $uri\/ =404;\n    }\n\n    # Deny access to git and hidden files\n    location ~ \/\\. {\n        deny all;\n        access_log off;\n        log_not_found off;\n    }\n\n    # Deny access to .git directory\n    location ^~ \/.git\/ {\n        deny all;\n        access_log off;\n        log_not_found off;\n    }\n}\n<\/code><\/pre>\n<p>This configuration:<\/p>\n<li>Enables directory listing so you can browse folders<\/li>\n<li>Sets `index.html` as the default landing page<\/li>\n<li>Blocks access to `.git` and hidden files for security<\/li>\n<h2>Step 4: Create a Landing Page<\/h2>\n<p>Create `index.html` in your workspace root directory:<\/p>\n<p>&#8220;`html<\/p>\n<p><!DOCTYPE html><br \/>\n<html lang=\"en\"><br \/>\n<head><br \/>\n    <meta charset=\"UTF-8\"><br \/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><br \/>\n    <title>Workspace | Your Name<\/title><\/p>\n<style>\n<p>body {<\/p>\n<p>font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;<\/p>\n<p>background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);<\/p>\n<p>min-height: 100vh;<\/p>\n<p>padding: 40px 20px;<\/p>\n<p>color: #333;<\/p>\n<p>}<\/p>\n<p>.container {<\/p>\n<p>max-width: 1200px;<\/p>\n<p>margin: 0 auto;<\/p>\n<p>}<\/p>\n<p>h1 {<\/p>\n<p>color: white;<\/p>\n<p>font-size: 2.5rem;<\/p>\n<p>margin-bottom: 10px;<\/p>\n<p>}<\/p>\n<p>.grid {<\/p>\n<p>display: grid;<\/p>\n<p>grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));<\/p>\n<p>gap: 20px;<\/p>\n<p>margin-top: 30px;<\/p>\n<p>}<\/p>\n<p>.card {<\/p>\n<p>background: white;<\/p>\n<p>border-radius: 12px;<\/p>\n<p>padding: 24px;<\/p>\n<p>box-shadow: 0 10px 30px rgba(0,0,0,0.2);<\/p>\n<p>transition: transform 0.3s ease, box-shadow 0.3s ease;<\/p>\n<p>text-decoration: none;<\/p>\n<p>color: inherit;<\/p>\n<p>}<\/p>\n<p>.card:hover {<\/p>\n<p>transform: translateY(-5px);<\/p>\n<p>box-shadow: 0 15px 40px rgba(0,0,0,0.3);<\/p>\n<p>}<\/p>\n<p>.card-icon {<\/p>\n<p>font-size: 2.5rem;<\/p>\n<p>margin-bottom: 15px;<\/p>\n<p>}<\/p>\n<p>.card-title {<\/p>\n<p>font-size: 1.3rem;<\/p>\n<p>font-weight: 600;<\/p>\n<p>margin-bottom: 8px;<\/p>\n<p>color: #1a1a2e;<\/p>\n<p>}<\/p>\n<p>.card-desc {<\/p>\n<p>color: #666;<\/p>\n<p>font-size: 0.95rem;<\/p>\n<p>line-height: 1.5;<\/p>\n<p>}<\/p>\n<p>.folder-badge {<\/p>\n<p>display: inline-block;<\/p>\n<p>background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);<\/p>\n<p>color: white;<\/p>\n<p>padding: 4px 12px;<\/p>\n<p>border-radius: 20px;<\/p>\n<p>font-size: 0.8rem;<\/p>\n<p>margin-top: 10px;<\/p>\n<p>}<\/p>\n<\/style>\n<p><\/head><br \/>\n<body><\/p>\n<div class=\"container\">\n<h1>\ud83d\udcbb My Workspace<\/h1>\n<div class=\"grid\">\n            <a href=\"\/blog\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\ud83d\udcdd<\/div>\n<div class=\"card-title\">Blog<\/div>\n<div class=\"card-desc\">Drafts, published posts, images, and scripts<\/div>\n<p>                <span class=\"folder-badge\">\/blog\/<\/span><br \/>\n            <\/a><br \/>\n            <a href=\"\/projects\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\ud83d\ude80<\/div>\n<div class=\"card-title\">Projects<\/div>\n<div class=\"card-desc\">Standalone projects and experiments<\/div>\n<p>                <span class=\"folder-badge\">\/projects\/<\/span><br \/>\n            <\/a><br \/>\n            <a href=\"\/skills\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\u26a1<\/div>\n<div class=\"card-title\">Skills<\/div>\n<div class=\"card-desc\">OpenClaw skills and automation workflows<\/div>\n<p>                <span class=\"folder-badge\">\/skills\/<\/span><br \/>\n            <\/a><br \/>\n            <a href=\"\/scripts\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\ud83d\udc0d<\/div>\n<div class=\"card-title\">Scripts<\/div>\n<div class=\"card-desc\">Python scripts and automation tools<\/div>\n<p>                <span class=\"folder-badge\">\/scripts\/<\/span><br \/>\n            <\/a><br \/>\n            <a href=\"\/tools\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\ud83d\udd27<\/div>\n<div class=\"card-title\">Tools<\/div>\n<div class=\"card-desc\">Config files and utilities<\/div>\n<p>                <span class=\"folder-badge\">\/tools\/<\/span><br \/>\n            <\/a><br \/>\n            <a href=\"\/memory\/\" class=\"card\"><\/p>\n<div class=\"card-icon\">\ud83e\udde0<\/div>\n<div class=\"card-title\">Memory<\/div>\n<div class=\"card-desc\">Daily notes and long-term memories<\/div>\n<p>                <span class=\"folder-badge\">\/memory\/<\/span><br \/>\n            <\/a>\n        <\/div>\n<\/p><\/div>\n<p><\/body><br \/>\n<\/html><\/p>\n<pre><code>\n\nCustomize the name and descriptions to match your workspace!\n\n## Step 5: Start the Server\n\nRun the following command from your workspace directory:\n\n```bash\ndocker compose -f docker-compose.workspace-server.yml up -d\n<\/code><\/pre>\n<p>The server will start automatically and restart if it crashes.<\/p>\n<h2>Step 6: Find Your Tailscale IP<\/h2>\n<p>On your VPS, run:<\/p>\n<p>&#8220;`bash<\/p>\n<p>ip a | grep -A 2 &#8220;tailscale&#8221; | grep &#8220;inet &#8221; | awk &#8216;{print $2}&#8217; | cut -d\/ -f1<\/p>\n<pre><code>\n\nYou'll see an output like `100.x.x.x`. That's your Tailscale IP.\n\n## Step 7: Access Your Workspace\n\nFrom any device connected to Tailscale, open your browser and navigate to:\n\n<\/code><\/pre>\n<p>http:\/\/YOUR_TAILSCALE_IP:8000<\/p>\n<pre><code>\n\nYou should see your landing page with cards linking to each directory. Click around, browse your files, and enjoy having your workspace available everywhere!\n\n## Security Considerations\n\nThis setup is designed to be secure:\n\n1. **Tailscale encryption**: All traffic is encrypted end-to-end using WireGuard\n2. **Read-only access**: The nginx container mounts files as read-only\n3. **Hidden files blocked**: The configuration denies access to `.git` and hidden files\n4. **Private network**: Tailscale keeps traffic off the public internet\n\n## Why Tailscale Instead of Public IP?\n\nUsing Tailscale has several advantages over exposing a public IP:\n\n- **No port forwarding needed**: Works behind NAT and firewalls\n- **Built-in encryption**: WireGuard protects all traffic\n- **Access control**: Only devices you approve can connect\n- **No DNS setup**: Use the IP directly or set up Tailscale MagicDNS\n- **Secure by default**: No public internet exposure\n\n## Advanced: Multiple Workspaces\n\nIf you have multiple workspaces, you can run multiple servers on different ports:\n\n```yaml\nports:\n  - \"8001:80\"\n<\/code><\/pre>\n<p>Just update the port mapping and configuration for each workspace.<\/p>\n<h2>Troubleshooting<\/h2>\n<p><strong>Can&#8217;t access the server:<strong><\/p>\n<li>Verify Tailscale is running on both devices: `tailscale status`<\/li>\n<li>Check the container is running: `docker ps`<\/li>\n<li>Test locally: `curl http:\/\/localhost:8000`<\/li>\n<p><strong>Container keeps restarting:<strong><\/p>\n<li>Check logs: `docker logs openclaw-workspace-server`<\/li>\n<li>Verify the workspace path is correct<\/li>\n<li>Ensure the `default.conf` file exists<\/li>\n<p><strong>Port blocked by ISP:<strong><\/p>\n<li>Try a different port (8001, 8081, etc.)<\/li>\n<li>Remember to update the port mapping in docker-compose.yml<\/li>\n<h2>Conclusion<\/h2>\n<p>With just a few files and Docker Compose, you&#8217;ve turned your OpenClaw workspace into a browsable, accessible environment. Whether you&#8217;re reviewing blog drafts from your phone, checking scripts on a tablet, or sharing work with a team member across the globe, your workspace is now just a click away.<\/p>\n<p>The beauty of this setup is its simplicity\u2014no complex firewall rules, no SSL certificates to manage, no DNS configuration. Tailscale handles the networking, Docker handles the serving, and you handle the creativity.<\/p>\n<p>Happy workspace browsing! \ud83d\ude80<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Serve Your OpenClaw <\/p>\n","protected":false},"author":2,"featured_media":1454,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[128,4],"tags":[],"class_list":["post-1441","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-memo"],"_links":{"self":[{"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/posts\/1441","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1441"}],"version-history":[{"count":5,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/posts\/1441\/revisions"}],"predecessor-version":[{"id":1456,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/posts\/1441\/revisions\/1456"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=\/wp\/v2\/media\/1454"}],"wp:attachment":[{"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/openclaw.helloai.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}