A local webserver for developers

Travis Build Status

devd: a local webserver for developers

screenshot

Install

Go to the releases page, download the package for your OS, and copy the binary to somewhere on your PATH.

If you have a working Go installation, you can also say

go get github.com/cortesi/devd/cmd/devd

Quick start

Serve the current directory, open it in the browser (-o), and livereload when files change (-l):

devd -ol .

Reverse proxy to http://localhost:8080, and livereload when any file in the src directory changes:

devd -w ./src http://localhost:8080

Using devd with modd

Modd is devd's sister project - a dev tool that runs commands and manages daemons in response to filesystem changes. Devd can be used with modd to rebuild a project and reload the browser when filesystem changes are detected.

Here's a quick example of a simple modd.conf file to illustrate.

src/** {
    prep: render ./src ./rendered
}

rendered/*.css ./rendered/*.html {
    daemon: devd -m ./rendered
}

The first block runs the render script whenever anything in the src directory changes. The second block starts a devd instance, and triggers livereload with a signal whenever a .css or .html file in the rendered directory changes.

See the modd project page for details.

Features

Cross-platform and self-contained

Devd is a single statically compiled binary with no external dependencies, and is released for macOS, Linux and Windows. Don't want to install Node or Python in that light-weight Docker instance you're hacking in? Just copy over the devd binary and be done with it.

Designed for the terminal

This means no config file, no daemonization, and logs that are designed to be read in the terminal by a developer. Logs are colorized and log entries span multiple lines. Devd's logs are detailed, warn about corner cases that other daemons ignore, and can optionally include things like detailed timing information and full headers.

Convenient

To make quickly firing up an instance as simple as possible, devd automatically chooses an open port to run on (unless it's specified), and can open a browser window pointing to the daemon root for you (the -o flag in the example above). It also has utility features like the -s flag, which auto-generates a self-signed certificate for devd, stores it in ~/.devd.certs and enables TLS all in one step.

Livereload

When livereload is enabled, devd injects a small script into HTML pages, just before the closing head tag. The script listens for change notifications over a websocket connection, and reloads resources as needed. No browser addon is required, and livereload works even for reverse proxied apps. If only changes to CSS files are seen, devd will only reload external CSS resources, otherwise a full page reload is done. This serves the current directory with livereload enabled:

devd -l .

You can also trigger livereload for files that are not being served, letting you reload reverse proxied applications when source files change. So, this command watches the src directory tree, and reverse proxies to a locally running application:

devd -w ./src http://localhost:8888

The -x flag excludes files from triggering livereload based on a pattern specification. The following command disables livereload for all files with the ".less" extension:

devd -x "**.less" -l .

When livereload is enabled (with the -L, -l or -w flags), devd responds to a SIGHUP by issuing a livereload notice to all connected browsers. This allows external tools, like devd's sister project modd, to trigger livereload. If livereload is not enabled, SIGHUP causes the daemon to exit.

The closing head tag must be found within the first 30kb of the remote file, otherwise livereload is disabled for the file.

Reverse proxy + static file server + flexible routing

Modern apps tend to be collections of web servers, and devd caters for this with flexible reverse proxying. You can use devd to overlay a set of services on a single domain, add livereload to services that don't natively support it, add throttling and latency simulation to existing services, and so forth.

Here's a more complicated example showing how all this ties together - it overlays two applications and a tree of static files. Livereload is enabled for the static files (-l) and also triggered whenever source files for reverse proxied apps change (-w):

devd -l \
-w ./src/ \
/=http://localhost:8888 \
/api/=http://localhost:8889 \
/static/=./assets

The route specification syntax is compact but powerful enough to cater for most use cases.

Light-weight virtual hosting

Devd uses a dedicated domain - devd.io - to do simple virtual hosting. This domain and all its subdomains resolve to 127.0.0.1, which we use to set up virtual hosting without any changes to /etc/hosts or other local configuration. Route specifications that don't start with a leading / are taken to be subdomains of devd.io. So, the following command serves a static site from devd.io, and reverse proxies a locally running app on api.devd.io:

devd ./static api=http://localhost:8888

Latency and bandwidth simulation

Want to know what it's like to use your fancy 5mb HTML5 app from a mobile phone in Botswana? Look up the bandwidth and latency here, and invoke devd like so (making sure to convert from kilobits per second to kilobytes per second and account for the location of your server):

devd -d 114 -u 51 -n 275 .

Devd tries to be reasonably accurate in simulating bandwidth and latency - it uses a token bucket implementation for throttling, properly handles concurrent requests, and chunks traffic up so data flow is smooth.

Routes

The devd command takes one or more route specifications as arguments. Routes have the basic format root=endpoint. Roots can be fixed, like "/favicon.ico", or subtrees, like "/images/" (note the trailing slash). Endpoints can be filesystem paths or URLs to upstream HTTP servers.

Here's a route that serves the directory ./static under /assets on the server:

/assets/=./static

To use a devd.io subdomain (which will resolve to 127.0.0.1), just add it to the the front of the root specification. We recognize subdomains by the fact that they don't start with a leading /. So, this route serves the /static directory under static.devd.io/assets:

static/assets=./static

Reverse proxy specifications are similar, but the endpoint specification is a URL. The following serves a local URL from the root app.devd.io/login:

app/login=http://localhost:8888

If the root specification is omitted, it is assumed to be "/", i.e. a pattern matching all paths. So, a simple directory specification serves the directory tree directly under devd.io:

devd ./static

Similarly, a simple reverse proxy can be started like this:

devd http://localhost:8888

There is also a shortcut for reverse proxying to localhost:

devd :8888

Serving default content for files not found

The --notfound flag can be passed multiple times, and specifies a set of routes that are consulted when a requested file is not found by the static file server. The basic syntax is root=path, where root has the same semantics as route specification. As with routes, the root= component is optional, and if absent is taken to be equal to /. The path is always relative to the static directory being served. When it starts with a leading slash (/), devd will only look for a replacement file in a single location relative to the root of the tree. Otherwise, it will search for a matching file by joining the specified path with all path components up to the root of the tree.

Let's illustrate this with an example. Say we have a /static directory as follows:

./static
├── bar
│   └── index.html
└── index.html

We can specify that devd should look for an index.html anywhere on the path to the root of the static tree as follows:

devd --notfound index.html  /static

Now, the following happens:

  • A request for /nonexistent.html returns the contents of /index.html
  • A request for /bar/nonexistent.html returns the contents of /bar/index.html
  • A request for /foo/bar/voing/index.html returns the contents of /index.html

We could instead specify an absolute path in the route, in which case the contents of /index.html would be returned for all the examples above:

devd --notfound /index.html  /static

Devd won't serve an over-ride page if the expected type of the incoming request doesn't match that of the override specification. We do this by looking at the file extension and expected MIME types of the over-ride and request, defaulting to text/html if the type couldn't be positively established. This prevents issues where, for instance, an HTML over-ride page might be served where images are expected.

Excluding files from livereload

The -x flag supports the following terms:

Term Meaning
* matches any sequence of non-path-separators
** matches any sequence of characters, including path separators
? matches any single non-path-separator character
[class] matches any single non-path-separator character against a class of characters
{alt1,...} matches a sequence of characters if one of the comma-separated alternatives matches

Any character with a special meaning can be escaped with a backslash (\). Character classes support the following:

Class Meaning
[abc] matches any single character within the set
[a-z] matches any single character in the range
[^class] matches any single character which does not match the class

About reverse proxying

Devd does not validate upstream SSL certificates when reverse proxying. For our use case, development servers will usually be running locally, often with self-signed certificates for testing. You shouldn't use devd in cases where upstream cert validation matters.

The X-Forwarded-Host and X-Forwarded-Proto headers are set to the devd server's address and protocol for reverse proxied traffic. You might need to enable support for this in your application for redirects and the like to work correctly.

Development

The scripts used to build this package for distribution can be found here. External packages are vendored using dep.

Owner
Comments
  • Ability to specify 404 page/handler

    Ability to specify 404 page/handler

    For better or worse, I'm using react-router with browserHistory on a project which turns hash routes (devd.io/#/foo) into prettier urls (devd.io/foo). This functionality requires specific setup in the server software and I do not believe it is currently possible to configure devd to support this.

    The recommended setup for nginx is to use the try_files directive to fall back on your react entry page if the file is not found (try_files $uri /index.html). I believe the simplest way to support this functionality in devd would be to allow for a 404 handler or fallback to be specified when the file server cannot find the specified resource. Perhaps a more robust way would be an extension to the routing syntax to allow for greater flexibility.

    Thank you for your consideration

  • Integrated self-test ?

    Integrated self-test ?

    I'm planning to create formula for homebrew for devd. For that, it would be good if devd can be tested somehow. Currently it's not easily possible. Maybe it's can be added functionality that would perform HEAD request to itself and validate some headers and exit with result code ? Or something a bit more complex: start with directory parameter in test mode, try to request some file and validate it by also reading from filesystem ?

    Or maybe something else in your opinion can be used as simple test of devd ?

  • Possible reverse proxy bug?

    Possible reverse proxy bug?

    When I serve my site like this (minimized from the real example):

    devd /veterans-employment-center/=http://localhost:8888/veterans-employment-center
    

    The reverse proxy asks for the correct URL, http://localhost:8888/veterans-employment-center/:

    $ ./serve.sh
    10:31:02: Listening on http://devd.io:8000 (127.0.0.1:8000)
    10:31:03: GET http://localhost:8888/veterans-employment-center/
      <- 404 Not Found 39B
    

    But says it can't find it. That URL is valid and works:

    $ curl http://localhost:8888/veterans-employment-center/
    <!DOCTYPE html>
    <html class="no-js" lang="en">
    <head>
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
    

    Is this a bug or am I doing something wrong?

  • devd -ol . returns error on Windows 7

    devd -ol . returns error on Windows 7

    I try to start devd following the example in the documentation but it always returns an error:

    devd is in c:\tools and my files are in a different folder e.g. c:\projects\test

    c:\tools\devd -ol .
    

    returns the following error:

    devd :error : could not watch routes for livereload: the syntax of the filename, foldername of volumename is incorrect
    

    I am using version 0.2 (on windows 7 64bit) When I specify the full pathname of the folder, it works.

    c:\tools\devd -ol c:\projects\test
    
  • Livereload broken on Linux in v0.8

    Livereload broken on Linux in v0.8

    In v0.8:

    % ./devd --debug -l . > /tmp/log &
    [1] 27072
    % echo foo >> index.html
    % cat /tmp/log
    00:44:02: Route / -> reads files from .
    00:44:02: Listening on http://devd.io:8000 (127.0.0.1:8000)
    

    In v0.7:

    % ./devd --debug -l . > /tmp/log &
    [1] 26755
    % echo foo >> index.html
    % cat /tmp/log
    00:42:47: Route / -> reads files from .
    00:42:47: Listening on http://devd.io:8000 (127.0.0.1:8000)
    00:42:51: livereload page, files changed: [index.html]
    
  • Script injection not working if head tag is missing

    Script injection not working if head tag is missing

    If the served html file does not have a head tag then the live reload script is not injected. I think it is enough to document this.

    This is a great tool, thank you.

  • Review set of vendored deps.

    Review set of vendored deps.

    @cortesi please review set of deps that are part of vendor/ directory. This set is not enough to build devd without fetching something from the network, thus devd 0.5 in homebrew still proposed to be built in "old way": Homebrew/homebrew-core/pull/182

  • Support build commands

    Support build commands

    It would be awesome if devd could be responsible for building as well as live reload. Essentially I would love to specify a pattern to watch and a command to execute if one of those files changed. I imagine the API could look something like:

    devd --livereload --watch ./build --srcs ./src --exec "make"
    

    I'm not sure what the exec and exec watch path would be.

  • Port number is missing from HTTP_HOST

    Port number is missing from HTTP_HOST

    Hello,

    devd is really a great idea, something I already searched for some time now.

    But when I tried it out on my development system, I had the issue, that the original port number used is not reflected in the HTTP_HOST. I understand, that there where an issue with a different customer, that had problems when the port number is not stripped. But wouldn't it make sense to provide an option for that behavior because at least in my setting, I want to redirect to a different page of my own web-site and the Django framework does create the URL from the HTTP_HOST -- which will be wrong without port number.

    Edit: I would do the change myself and fork the project, but currently I am not working with go, so it would be a big overhead for me. Also I think, that such a switch would be beneficial also for other people using Django or similar frameworks.

    Best Regards and thank you for that great tool!

    /juergen

  • Does websocket protocol work?

    Does websocket protocol work?

    Hi,

    Love devd!

    I'm having trouble reverse proxying the ws protocol. The following runs:

    devd -H /api/=http://localhost:8080/api /ws/=http://localhost:8080/ws public/
    

    ... but attempts to access the websocket (which work without devd) fail with:

    WebSocket connection to 'ws://localhost:8000/ws' failed: Error during WebSocket handshake: Unexpected response code: 301
    

    Thanks! A

  • Install dependencies in build script

    Install dependencies in build script

    This is the commit I'm least sure about, but it was a pain to install all these dependencies manually. Does this seem like a reasonable way to accomplish this? Ought we to create a separate dependency install script, so that we don't run all these "go get"s on every build?

    Should I create a simple makefile to speed up the build? Make could recognize that only source files had changed and avoid the go get overhead.

  • Be compatible with HTTP/2

    Be compatible with HTTP/2

    devd has the ability to serve content with TLS, it would be nice if HTTP/2 was enabled in that case to allow browsers to use it and benefit from it. This is useful for development environment to test how an app reacts to it.

  • Can't serve a directory and watching a sub-directory

    Can't serve a directory and watching a sub-directory

    I have the following directory structure:

    $ tree .
    .
    ├── build
    │   └── foo.js
    └── index.html
    
    $ cat index.html
    <html>
      <head>
        <title>foo</title>
      </head>
      <body>
      </body>
      <script>
        console.log(new Date().toTimeString());
      </script>
    </html>
    

    I would like devd to (1) serve files from the top-directory (basically index.html) and (2) reload when build/foo.js (or any other file in build/ changes). In particular, I don't want devd to reload if index.html (or any other file outside of build/) is changed.

    I have tried several alternatives with no success:

    • devd -w build/ -l .: reloads when index.html is changed (and I don't want that)
    • devd -w build/ -L .: never reloads, even if build/foo.js is changed
  • Compatiblity with future Go versions

    Compatiblity with future Go versions

    Just a heads up that Go 1.17 (and the just released 1.16 without first changing GO111MODULE) won't support builds that aren't in module-aware mode.

    The master build should work but the last tag (v0.9) does not. Is it possible you can tag a new release for this?

    https://blog.golang.org/go116-module-changes

  • devd doesn't listen if livewatch is specified

    devd doesn't listen if livewatch is specified

    I have devd 0.9 on Arch Linux, installed via the AUR. I usually use devd like this:

    devd -a -l -p 8000 ~/site/
    

    After updating devd recently it stopped working; devd would start up but I couldn't connect. I played around with flags and it seems like if I use the -l switch it never starts listening on a port (checked with lsof). The only output is Route / -> reads files from ....

    If take away the -l flag it starts listening as usual.

    Am I doing something wrong?

Simple wrapper for google/pprof to run as webserver
Simple wrapper for google/pprof to run as webserver

pprof-webserver simple wrapper for google/pprof to run as webserver left column shows list of profiles stored on the server new profiles can be upload

Jan 4, 2022
Golang-redis-webserver - Web server using redis

Web Server using Redis Api REST Database SQLITE3 Cache Redis # Creating record s

Jun 19, 2022
A feature flag solution, with only a YAML file in the backend (S3, GitHub, HTTP, local file ...), no server to install, just add a file in a central system and refer to it. 🎛️
A feature flag solution, with only a YAML file in the backend (S3, GitHub, HTTP, local file ...), no server to install, just add a file in a central system and refer to it. 🎛️

??️ go-feature-flag A feature flag solution, with YAML file in the backend (S3, GitHub, HTTP, local file ...). No server to install, just add a file i

Dec 29, 2022
A local server with real-time reload function designed for static website preview or development

中文 | English ?? 介绍 reserver 是一款为静态网站预览或开发设计的具有实时重新加载功能的本地服务器。 其主要运用场景为: 单页应用的预览(例如Vue编译之后的项目不可以直接通过file://协议进行访问) 具有ajax请求的页面(因浏览器安全限制,默认禁止file://协议进行

Aug 23, 2022
Multi cluster kubernetes dashboard with batteries included. Build by developers, for developers.

kubetower Multi cluster kubernetes dashboard with batteries included. Built by developers, for developers. Features Restart deployments with one click

Nov 28, 2022
Tiny Go webserver that prints os information and HTTP request to output

whoami Tiny Go webserver that prints os information and HTTP request to output Usage Paths /data?size=n[&unit=u]: creates a response with a size n. Th

Nov 2, 2021
A hack example to servce file as a webserver with a Google Cloud Functions

Overview This project is a hack example to servce file as a webserver with a Google Cloud Functions (normally single purpose, only one entry point). I

Nov 26, 2021
Webserver I built to serve Infura endpoints. Deployable via k8s and AWS EKS. Load testable via k6 tooling, and montiorable via prometheus and grafana

Infura Web Server Welcome to my verion of the take home project. I've created a webserver written in go to serve Infura api data over 3 possible data

Nov 15, 2022
Webserver Log4j Honeypot With Golang

Webserver Log4j Honeypot This honeypots runs fake Webserver waiting to be exploited. Payload classes are saved to payloads directory. Forked from http

Dec 17, 2021
Raspberry Pi Zero W IR remote webserver for Cambridge Audio CXA81 Amplifier

CXA81-IR-Remote-Server About The Project I initially wanted to control my Cambri

Dec 27, 2021
Simple wrapper for google/pprof to run as webserver
Simple wrapper for google/pprof to run as webserver

pprof-webserver simple wrapper for google/pprof to run as webserver left column shows list of profiles stored on the server new profiles can be upload

Jan 4, 2022
Golang-redis-webserver - Web server using redis

Web Server using Redis Api REST Database SQLITE3 Cache Redis # Creating record s

Jun 19, 2022
⚡️ A dev tool for microservice developers to run local applications and/or forward others from/to Kubernetes SSH or TCP
⚡️ A dev tool for microservice developers to run local applications and/or forward others from/to Kubernetes SSH or TCP

Your new microservice development environment friend. This CLI tool allows you to define a configuration to work with both local applications (Go, Nod

Jan 4, 2023
Stackie enables developers to configure their local environment/toolchain with ease.

Stackie enables developers to configure their local environment/toolchain with ease. Made for Pulumi CLI, Google Cloud Platform (gcloud), and Amazon Web Services (aws-cli).

Sep 10, 2021
Open-Local is a local disk management system composed of multiple components.
Open-Local is a local disk management system composed of multiple components.

Open-Local is a local disk management system composed of multiple components. With Open-Local, using local storage in Kubernetes will be as simple as centralized storage.

Dec 30, 2022
Local Storage is one of HwameiStor components. It will provision the local LVM volume.
Local Storage is one of HwameiStor components. It will provision the local LVM volume.

Local Storage Module English | Simplified_Chinese Introduction Local Storage is one of modules of HwameiStor which is a cloud native local storage sys

Aug 6, 2022
A STOMP Client package for go developers, supporting all STOMP specification levels.

stompngo - A STOMP 1.0, 1.1 and 1.2 Client Package Features Full support of STOMP protocols: Protocol Level 1.0 Protocol Level 1.1 Protocol Level 1.2

Oct 19, 2022
Lightweight service virtualization/API simulation tool for developers and testers
Lightweight service virtualization/API simulation tool for developers and testers

API simulations for development and testing Hoverfly is a lightweight, open source API simulation tool. Using Hoverfly, you can create realistic simul

Dec 28, 2022
Go library for accessing trending repositories and developers at Github.
Go library for accessing trending repositories and developers at Github.

go-trending A package to retrieve trending repositories and developers from Github written in golang. This package were inspired by rochefort/git-tren

Dec 21, 2022
:bento: Highly Configurable Terminal Dashboard for Developers and Creators
:bento: Highly Configurable Terminal Dashboard for Developers and Creators

DevDash is a highly configurable terminal dashboard for developers and creators who want to choose and display the most up-to-date metrics they need,

Jan 3, 2023