Static Web Server - a very small and fast production-ready web server suitable to serve static web files or assets

Overview

Static Web Server

A blazing fast and asynchronous web server for static files-serving

Overview

Static Web Server (or SWS abbreviated) is a very small and fast production-ready web server suitable to serve static web files or assets.

It is focused on lightness and easy to use principles but keeping high performance and safety powered by The Rust Programming Language.

Written on top of Hyper and Tokio runtime. It provides concurrent and asynchronous networking abilities as well as the latest HTTP/1 - HTTP/2 implementations.

It's cross-platform and available for Linux, macOS, Windows and FreeBSD (x86/x86_64, ARM/ARM64) as well as Docker.

static-web-server

Features

  • Built with Rust which is focused on safety, speed and concurrency.
  • Memory safe and very reduced CPU and RAM overhead.
  • Blazing fast static files-serving and asynchronous powered by latest Hyper, Tokio and a set of awesome crates.
  • Single 4MB (uncompressed) and fully static binary with no dependencies (Musl libc). Suitable for running on any Linux distro or Docker container.
  • Optional GZip, Deflate or Brotli compression for text-based web files only.
  • Compression on demand via Accept-Encoding header.
  • Partial Content Delivery support for byte-serving of large files.
  • Optional Cache Control headers for assets.
  • Termination signal handling with graceful shutdown ability and grace period.
  • HTTP/2 + TLS support.
  • Security headers for HTTP/2 by default.
  • HEAD responses.
  • Lightweight and configurable logging via tracing crate.
  • Customizable number of worker threads.
  • Optional directory listing.
  • CORS support.
  • Basic HTTP Authentication.
  • Customizable HTTP Response Headers for specific file requests via glob patterns.
  • Fallback pages for 404 errors useful for Single-page applications.
  • Run the server as Windows Service.
  • Configurable using CLI arguments, environment variables or a file.
  • Default and custom error pages.
  • First-class Docker support. Scratch and latest Alpine Linux Docker images available.
  • Ability to accept a socket listener as a file descriptor for use in sandboxing and on-demand applications (E.g systemd).
  • Cross-platform. Binaries available for Linux, macOS, Windows & FreeBSD x86_64 / ARM.

Documentation

For more details about the API, usage and examples please have a look at The Documentation Website.

Releases

Notes

  • If you're looking for v1 please go to 1.x branch.
  • If you want to migrate from v1 to v2 please take a look at Migrating from v1 to v2 release.

Contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in current work by you, as defined in the Apache-2.0 license, shall be dual licensed as described below, without any additional terms or conditions.

Feel free to send some Pull request or file an issue.

License

This work is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).

© 2019-present Jose Quintana

Comments
  • Support inheriting TCP listener from parent process via fd0

    Support inheriting TCP listener from parent process via fd0

    Hi,

    Here's a rough draft PR. Not for merging yet, just for possible discussion.

    • I'm not really happy with the option parsing. Having just a switch e.g. static-web-server --inherit-listener seems reasonable, but it doesn't look like you can do that and also have an ENV variable control the same thing. I'll have a closer look at this.
    • Probably better to split off the transition to a separated bind call into a separate commit.
    • Not sure if the trace output is OK or not?
    • Error handling should be improved.

    Closes #36

    enhancement v2 
    opened by tim-seoss 17
  • Breaks if path is behind as symlink and the symlink is changed

    Breaks if path is behind as symlink and the symlink is changed

    I am trying to use this in conjunction with https://github.com/kubernetes/git-sync

    Namely, I've got a k8s pod that has 2 containers, git-sync and your image. I've got a shared emptyDir volume shared between the two.

    The way git-sync works is: It checks out the revision under rev-<hash>, and creates a symlink name-of-repo -> rev-<hash>. And then periodically checks for new changes, checks out new rev-<hash> and repoints the symlink.

    I am pointing your image to serve name-of-repo/config, and initially it works, but I observe that once git-sync checks out a new revision, your image starts returning 404s.

    I am no rust expert, but I believe as you wire your server up, you are probably resolving the symlink to a real path along the way, hence prevent any serving of files once the symlink is changed.

    v1 not-a-bug 
    opened by AudriusButkevicius 13
  • Use relative paths in directory listing URLs

    Use relative paths in directory listing URLs

    I run SWS behind an ingress controller in Kubernetes and typically use subpaths on the ingress, rewriting paths relative to / when proxying to SWS. This has been working perfectly, because of course serving static files is a relatively simple task. :)

    I had a need to enable directory listings and noticed the URLs become invalid with this configuration due to the use of absolute paths relative to /

    The simplest fix is to use relative URLs (./filename) in the directory listing HTML. The user's browser will take care of the rest, providing valid URLs that get cleanly rewritten by the upstream proxy.

    Then things should work properly regardless of whether SWS is behind a proxy subpath, and no additional user configuration is required. I don't see any downside?

    enhancement v2 
    opened by jtackaberry 12
  • Configurable grace period on SIGTERM

    Configurable grace period on SIGTERM

    Problem

    When hosting static-web-server in Kubernetes, there is a subtle race that exists during rollouts that causes upstream endpoint-based traffic steering (such as nginx-ingress controller) to fail requests. With nginx upstream, for example, this results in a 502 Bad Gateway.

    Suppose static-web-server is run within a Kubernetes Deployment. The race is as follows:

    1. Update the deployment resource, or execute kubectl rollout restart, which causes new replacement pods to spin up.
    2. The new pods come up and pass readiness checks. Traffic starts being directed to them.
    3. Kubernetes begins terminating old pods. static-web-server dutifully responds to SIGTERM by shutting down immediately.
    4. The Service or Ingress takes a moment to notice the updates to the available Endpoints. During this time, traffic is still being directed to the dying or dead pods.
    5. The Service or Ingress updates to reflect the change in endpoints and life returns to normal.

    There is a discussion of this race over at https://github.com/kubernetes/ingress-gce/issues/769

    One could argue Kubernetes should be providing the appropriate constructs to solve this problem (i.e. by withdrawing the to-be-terminated pods from the available endpoints to prevent traffic from going to pods before it kills them). But the Kubernetes philosophy here appears to be to delegate this responsibility to the underlying workloads, for better or worse.

    Feature Request

    To address the above issue, I propose that static-web-server provides a configurable grace period in seconds, whereupon receiving SIGTERM it continues to respond to requests during the grace period, but issues Connection: close for all requests, even if Connection: keep-alive is requested. Once the configurable grace period has elapsed, then exit as usual.

    This is basically the suggestion in this comment by Bowei Du on the Kubernetes team.

    enhancement v2 
    opened by jtackaberry 12
  • Configurable grace period support after a `SIGTERM` signal caught

    Configurable grace period support after a `SIGTERM` signal caught

    Description

    This PR introduces a new --grace-period option that happens right after a SIGTERM in order to delay server's graceful showdown.

    -q, --grace-period <grace-period>
    Defines a grace period in seconds after a `SIGTERM` signal is caught which will delay the server before to
    shut it down gracefully. 255 seconds maximum [env: SERVER_GRACE_PERIOD=]  [default: 0]
    

    Related Issue

    No

    Motivation and Context

    Feature request #79

    How Has This Been Tested?

    Using the following command and options

    static-web-server -p 8787 -d docker/public/ -g trace -q 10
    

    Note: The logs below have been split out for better understanding.

    1. Server starts with a grace period of 10 secs
    2022-02-01T15:21:41.222866Z  INFO static_web_server::server: bound to TCP socket [::]:8787
    2022-02-01T15:21:41.222950Z  INFO static_web_server::server: runtime worker threads: 4
    2022-02-01T15:21:41.222973Z  INFO static_web_server::server: security headers: enabled=false
    2022-02-01T15:21:41.222991Z  INFO static_web_server::server: auto compression: enabled=true
    2022-02-01T15:21:41.223017Z  INFO static_web_server::server: directory listing: enabled=false
    2022-02-01T15:21:41.223042Z  INFO static_web_server::server: directory listing order code: 6
    2022-02-01T15:21:41.223058Z  INFO static_web_server::server: cache control headers: enabled=true
    2022-02-01T15:21:41.223100Z  INFO static_web_server::server: basic authentication: enabled=false
    2022-02-01T15:21:41.223150Z TRACE mio::poll: registering event source with poller: token=Token(1), interests=READABLE | WRITABLE    
    2022-02-01T15:21:41.223194Z TRACE mio::poll: registering event source with poller: token=Token(2), interests=READABLE | WRITABLE    
    2022-02-01T15:21:41.223402Z TRACE mio::poll: registering event source with poller: token=Token(3), interests=READABLE | WRITABLE    
    2022-02-01T15:21:41.223544Z  INFO Server::start_server{addr_str="[::]:8787" threads=4}: static_web_server::server: close time.busy=0.00ns time.idle=11.3µs
    2022-02-01T15:21:41.223599Z  INFO static_web_server::server: listening on http://[::]:8787
    2022-02-01T15:21:41.223622Z  INFO static_web_server::server: press ctrl+c to shut down the server
    
    1. Server receives one request
    2022-02-01T15:21:50.015015Z TRACE mio::poll: registering event source with poller: token=Token(4), interests=READABLE | WRITABLE    
    2022-02-01T15:21:50.015353Z TRACE hyper::proto::h1::conn: Conn::read_head
    2022-02-01T15:21:50.015442Z TRACE hyper::proto::h1::io: received 93 bytes
    2022-02-01T15:21:50.015617Z TRACE parse_headers: hyper::proto::h1::role: Request.parse bytes=93
    2022-02-01T15:21:50.015714Z TRACE parse_headers: hyper::proto::h1::role: Request.parse Complete(93)
    2022-02-01T15:21:50.015854Z TRACE parse_headers: hyper::proto::h1::role: close time.busy=264µs time.idle=25.0µs
    2022-02-01T15:21:50.015939Z DEBUG hyper::proto::h1::io: parsed 3 headers
    2022-02-01T15:21:50.015970Z DEBUG hyper::proto::h1::conn: incoming body is empty
    2022-02-01T15:21:50.016070Z TRACE static_web_server::static_files: dir? base="docker/public/", route="/assets/main.js"
    2022-02-01T15:21:50.016262Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: KeepAlive, writing: Init, keep_alive: Busy }
    2022-02-01T15:21:50.016379Z TRACE static_web_server::static_files: dir: "docker/public/assets/main.js"
    2022-02-01T15:21:50.016464Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: KeepAlive, writing: Init, keep_alive: Busy }
    2022-02-01T15:21:50.016794Z TRACE encode_headers: hyper::proto::h1::role: Server::encode status=200, body=Some(Unknown), req_method=Some(HEAD)
    2022-02-01T15:21:50.016869Z TRACE encode_headers: hyper::proto::h1::role: server body forced to 0; method=Some(HEAD), status=200
    2022-02-01T15:21:50.016932Z TRACE encode_headers: hyper::proto::h1::role: close time.busy=140µs time.idle=15.4µs
    2022-02-01T15:21:50.016999Z TRACE hyper::proto::h1::dispatch: no more write body allowed, user body is_end_stream = false
    2022-02-01T15:21:50.017122Z DEBUG hyper::proto::h1::io: flushed 223 bytes
    2022-02-01T15:21:50.017158Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: Init, writing: Init, keep_alive: Idle }
    2022-02-01T15:21:50.017377Z TRACE hyper::proto::h1::conn: Conn::read_head
    2022-02-01T15:21:50.017438Z TRACE hyper::proto::h1::io: received 0 bytes
    2022-02-01T15:21:50.017470Z TRACE hyper::proto::h1::io: parse eof
    2022-02-01T15:21:50.017506Z TRACE hyper::proto::h1::conn: State::close_read()
    2022-02-01T15:21:50.017532Z DEBUG hyper::proto::h1::conn: read eof
    2022-02-01T15:21:50.017565Z TRACE hyper::proto::h1::conn: State::close_write()
    2022-02-01T15:21:50.017588Z TRACE hyper::proto::h1::conn: State::close_read()
    2022-02-01T15:21:50.017616Z TRACE hyper::proto::h1::conn: State::close_write()
    2022-02-01T15:21:50.017650Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: Closed, writing: Closed, keep_alive: Disabled }
    2022-02-01T15:21:50.017727Z TRACE hyper::proto::h1::conn: shut down IO complete
    2022-02-01T15:21:50.017774Z TRACE mio::poll: deregistering event source from poller    
    
    1. Server receives an intentional ctrl+c Note the Grace period of 10 second(s) after the SIGTERM log entry
    ^C2022-02-01T15:21:58.756116Z  INFO static_web_server::signals: SIGTERM, SIGINT or SIGQUIT signal caught
    2022-02-01T15:21:58.756301Z  INFO static_web_server::signals: Grace period of 10 second(s) after the SIGTERM
    
    1. Server receives another request completed sucessfully
    2022-02-01T15:22:02.685889Z TRACE mio::poll: registering event source with poller: token=Token(16777220), interests=READABLE | WRITABLE    
    2022-02-01T15:22:02.686097Z TRACE hyper::proto::h1::conn: Conn::read_head
    2022-02-01T15:22:02.686159Z TRACE hyper::proto::h1::io: received 94 bytes
    2022-02-01T15:22:02.686322Z TRACE parse_headers: hyper::proto::h1::role: Request.parse bytes=94
    2022-02-01T15:22:02.686393Z TRACE parse_headers: hyper::proto::h1::role: Request.parse Complete(94)
    2022-02-01T15:22:02.686501Z TRACE parse_headers: hyper::proto::h1::role: close time.busy=199µs time.idle=28.4µs
    2022-02-01T15:22:02.686561Z DEBUG hyper::proto::h1::io: parsed 3 headers
    2022-02-01T15:22:02.686584Z DEBUG hyper::proto::h1::conn: incoming body is empty
    2022-02-01T15:22:02.686658Z TRACE static_web_server::static_files: dir? base="docker/public/", route="/assets/main.css"
    2022-02-01T15:22:02.686810Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: KeepAlive, writing: Init, keep_alive: Busy }
    2022-02-01T15:22:02.686954Z TRACE static_web_server::static_files: dir: "docker/public/assets/main.css"
    2022-02-01T15:22:02.687026Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: KeepAlive, writing: Init, keep_alive: Busy }
    2022-02-01T15:22:02.687292Z TRACE encode_headers: hyper::proto::h1::role: Server::encode status=200, body=Some(Unknown), req_method=Some(HEAD)
    2022-02-01T15:22:02.687356Z TRACE encode_headers: hyper::proto::h1::role: server body forced to 0; method=Some(HEAD), status=200
    2022-02-01T15:22:02.687411Z TRACE encode_headers: hyper::proto::h1::role: close time.busy=120µs time.idle=12.9µs
    2022-02-01T15:22:02.687469Z TRACE hyper::proto::h1::dispatch: no more write body allowed, user body is_end_stream = false
    2022-02-01T15:22:02.687583Z DEBUG hyper::proto::h1::io: flushed 210 bytes
    2022-02-01T15:22:02.687638Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: Init, writing: Init, keep_alive: Idle }
    2022-02-01T15:22:02.687816Z TRACE hyper::proto::h1::conn: Conn::read_head
    2022-02-01T15:22:02.687872Z TRACE hyper::proto::h1::io: received 0 bytes
    2022-02-01T15:22:02.687897Z TRACE hyper::proto::h1::io: parse eof
    2022-02-01T15:22:02.687918Z TRACE hyper::proto::h1::conn: State::close_read()
    2022-02-01T15:22:02.687937Z DEBUG hyper::proto::h1::conn: read eof
    2022-02-01T15:22:02.687955Z TRACE hyper::proto::h1::conn: State::close_write()
    2022-02-01T15:22:02.687974Z TRACE hyper::proto::h1::conn: State::close_read()
    2022-02-01T15:22:02.687990Z TRACE hyper::proto::h1::conn: State::close_write()
    2022-02-01T15:22:02.688011Z TRACE hyper::proto::h1::conn: flushed({role=server}): State { reading: Closed, writing: Closed, keep_alive: Disabled }
    2022-02-01T15:22:02.688074Z TRACE hyper::proto::h1::conn: shut down IO complete
    2022-02-01T15:22:02.688116Z TRACE mio::poll: deregistering event source from poller    
    
    1. Server's 10 secs grace period elapsed so delegate server's graceful shutdown
    2022-02-01T15:22:08.757722Z  INFO static_web_server::signals: Grace period has elapsed
    2022-02-01T15:22:08.757845Z  INFO static_web_server::signals: Delegating server's graceful shutdown
    2022-02-01T15:22:08.757948Z TRACE mio::poll: deregistering event source from poller    
    2022-02-01T15:22:08.758197Z DEBUG hyper::server::shutdown: signal received, starting graceful shutdown
    2022-02-01T15:22:08.758347Z TRACE mio::poll: deregistering event source from poller    
    2022-02-01T15:22:08.758844Z TRACE mio::poll: deregistering event source from poller    
    2022-02-01T15:22:08.759118Z  WARN static_web_server::server: termination signal caught, shutting down the server execution
    

    Screenshots (if appropriate):

    No

    enhancement v2 
    opened by joseluisq 11
  • Permission denied when running as non root user with Docker

    Permission denied when running as non root user with Docker

    Warning: I am not a Rust user and do not understand why the below is happening, nor am I amble to debug the ccode

    While trying to use the below Dockerfile to run the static-web-server as a non root user.

    FROM joseluisq/static-web-server:1.15.0-alpine as base
    
    # simcore-user uid=8004(scu) gid=8004(scu) groups=8004(scu)
    ENV SC_USER_ID=8004 \
        SC_USER_NAME=scu
    
    RUN adduser -D -u ${SC_USER_ID} -s /bin/sh -h /home/${SC_USER_NAME} ${SC_USER_NAME}
    
    # changing ownership of static-web-server files
    RUN chown -R ${SC_USER_NAME}:${SC_USER_NAME} /entrypoint.sh
    RUN chown -R ${SC_USER_NAME}:${SC_USER_NAME} /usr/local/bin/static-web-server
    RUN chown -R ${SC_USER_NAME}:${SC_USER_NAME} /public
    RUN chmod +x /usr/local/bin/static-web-server
    
    USER ${SC_USER_NAME}
    

    I get the following error

    thread 'main' panicked at 'Io(Os { code: 13, kind: PermissionDenied, message: "Permission denied" })', src/server.rs:72:25
    stack backtrace:
       0:     0x7fae3dfd594c - <unknown>
       1:     0x7fae3df5738c - <unknown>
       2:     0x7fae3dfd4e01 - <unknown>
       3:     0x7fae3dfd47c0 - <unknown>
       4:     0x7fae3dfd3fe9 - <unknown>
       5:     0x7fae3dff200d - <unknown>
       6:     0x7fae3dff1f7c - <unknown>
       7:     0x7fae3dff1f2d - <unknown>
       8:     0x7fae3dff1e70 - <unknown>
       9:     0x7fae3dfaaa32 - <unknown>
      10:     0x7fae3df027a7 - <unknown>
      11:     0x7fae3df01233 - <unknown>
      12:     0x7fae3df02ca2 - <unknown>
    make: *** [Makefile:18: run] Error 139
    

    Looks like src/server.rs:72:25 is pointing to a piece of code just loading the files https://github.com/joseluisq/static-web-server/blob/5cede7e92ab17ad51e93db7ad2b00edd88bf0cbd/src/server.rs#L69-L75

    If you open a shell into the container you can see the files inside the /public exist and belong to the correct user

    $ ls -lah /public/
    total 32K
    drwxr-xr-x    1 scu      scu         4.0K Apr 20 07:04 .
    drwxr-xr-x    1 root     root        4.0K May 27 07:46 ..
    -rw-r--r--    1 scu      scu          152 Apr 20 06:56 404.html
    -rw-r--r--    1 scu      scu          175 Apr 20 06:56 50x.html
    drwxr-xr-x    1 scu      scu         4.0K Apr 20 06:56 assets
    -rw-r--r--    1 scu      scu          483 Apr 20 06:56 index.html
    

    How to test

    git clone https://github.com/GitHK/issue-static-web-server.git
    cd issue-static-web-server
    make build
    make run
    

    Repo to reproduce the issue: https://github.com/GitHK/issue-static-web-server

    v1 not-a-bug 
    opened by GitHK 11
  • Unable to set password

    Unable to set password

    I created a test password with the apache command. Is there another way to create the password without depending on apache?

    root@dd55d312d133:/# htpasswd -nbBC5 "user01" "teste123"
    user01:$2y$05$IAu7m5jhbpQqzSv1u7JjGO3MrkVMUXXGY7a245klF55gifHjMZpOK
    
    container_name: sws-tt
        restart: always
        environment:
          - SERVER_DIRECTORY_LISTING=true
          - SERVER_BASIC_AUTH='user01:$2y$05$IAu7m5jhbpQqzSv1u7JjGO3MrkVMUXXGY7a245klF55gifHjMZpOK'
          # Nota: esses envs são personalizáveis, mas também opcionais
    
    ubuntu@vtrinity:~/Docker/SWS$ docker-compose ps
    WARN[0000] The "IAu7m5jhbpQqzSv1u7JjGO3MrkVMUXXGY7a245klF55gifHjMZpOK" variable is not set. Defaulting to a blank string. 
    invalid interpolation format for services.sws-tt.environment.[]: "SERVER_BASIC_AUTH='user01:$$2y$05$IAu7m5jhbpQqzSv1u7JjGO3MrkVMUXXGY7a245klF55gifHjMZpOK'". You may need to escape any $ with another $.
    
    question v2 not-a-bug 
    opened by talesam 10
  • feat: added application/wasm to compression file list

    feat: added application/wasm to compression file list

    application/wasm added as a plain text type for compression

    Motivation and Context

    application/wasm are plain text files and can be effectively compressed by gzip or brotli to speedup their download.

    How Has This Been Tested?

    No need to test.

    enhancement v2 
    opened by acelot 10
  • CORS support

    CORS support

    I could be wrong, but it seems that this server doesn't support CORS out-of-the-box. My guess is that it should be relatively simple to implement it with usage iron-cors.

    enhancement 
    opened by kirillt 10
  • Issue with volume in unRAID

    Issue with volume in unRAID

    First off, I don't know if it's an unRAID, Docker or the static-web-server issue. I'll post this issue in unRAID forum too.

    The issue is that the static-web-server uses the VOLUME ["/public"] and I bind some paths into the container from unRAID which fails to umount when stopping the array. In unRAID it's called path as for the -v /somedir:/public argument and array manages the HDD mounting and shares. The shares in unRAID are located in /mnt/user/<sharename>.

    I've bind 2 shared folder from unRAID into a subfolder in /public:

    • /mnt/user/movies to /public/movies
    • /mnt/user/series to /public/series

    It's working fine so far until I want to shutdown the server or stop the array. unRAID does these following steps:

    • stop containers graceful
    • stop docker
    • umount all shares
    • stop the array

    Docker stops fine but umounting all the shares fails here because static-web-server uses VOLUME ["/public"] which creates a new volume by docker into /var/lib/docker/volumes/<volume>/_data and the both binds of /public/movies and /public/series are mounted into this folder. When docker stops the binds are not linked anymore still unRAID sees the binding between them and cannot umount the shares. To do the graceful shutdown I manually umounting both of the binds directly in the /var/lib/docker/volumes/<volume>/_data_/movies, kill /dev/loop2 then unRAID is able to umount all /mnt/user shares. https://github.com/joseluisq/static-web-server/blob/d165213f375b5394736c97d68b348818d79b2d4a/docker/scratch/Dockerfile#L18

    If static-web-server wouldn't use VOLUME ["/public"] thus wouldn't create a volume under /var/lib/docker/volumes/<volume> and the bind goes directly into the docker process so that after stopping of docker no dead mounting exists.

    enhancement not-a-bug 
    opened by bergi9 9
  • socket activation (accept tcp listener file descriptor instead of binding to a tcp port)

    socket activation (accept tcp listener file descriptor instead of binding to a tcp port)

    Firstly, thanks for writing static-web-server - it's something I've been wanting for a while!

    Whilst looking at #35 I investigated how easy it would be to offer a socket activation model, as an alternative to binding to TCP port manually.

    In this context it would mean that the parent process of static-web-server (e.g. inetd, systemd, or possibly Apple launchd) would open a TCP socket listener, and then pass the file descriptor for this listener to static-web-server. In it's simplest form (and the model use by inetd), static-web-server would inherit the file descriptor for the TCP listener as it's standard input file descriptor (FD 0). There is a Rust crate called listenfd designed to handle this situation (making the passed-in FD available as an io::Result<Option<TcpListener>>).

    In the context of #35, this would allow:

    • Static-web-server to bind to a port number below 1024 whilst not running as root (I know there are other methods to do this e.g. using firewalls and proxies, but this is probably the lowest overhead one).
    • Restarting of the static-web-server without service interruption (e.g. for configuration change, or on SSL certificate renewal etc.) via https://www.freedesktop.org/software/systemd/man/systemd.socket.html#FlushPending=
    • The use of various advanced socket binding options supported by systemd (e.g. FreeBind) without adding more code to static-web-server or warp to handle these.
    • Further sandboxing of static-web-server from the host's network e.g. ref https://www.freedesktop.org/software/systemd/man/systemd.socket.html :

    All network sockets allocated through .socket units are allocated in the host's network namespace (see network_namespaces(7)). This does not mean however that the service activated by a configured socket unit has to be part of the host's network namespace as well. It is supported and even good practice to run services in their own network namespace (for example through PrivateNetwork=, see systemd.exec(5)), receiving only the sockets configured through socket-activation from the host's namespace. In such a set-up communication within the host's network namespace is only permitted through the activation sockets passed in while all sockets allocated from the service code itself will be associated with the service's own namespace, and thus possibly subject to a much more restrictive configuration.

    Unfortunately using this model with Warp isn't as straightforward as I'd hoped, although it can be done via hyper as shown in this example:

    https://github.com/rusty-crab/warp-api-starter-template/blob/833ca24994bd0a8e197332aee7df24eb687c84d1/src/main.rs#L172

    (this uses the listenfd crate: https://docs.rs/listenfd/0.3.3/listenfd/index.html ).

    Because static-web-server is already using a forked version of warp (and I'm not at all familiar with hyper and warp), I thought it best to just note this investigation at this point, rather than ploughing in and adding this feature to static-web-server.

    Any thoughts?

    enhancement help wanted v2 
    opened by tim-seoss 9
  • Add Android targets support

    Add Android targets support

    Is your feature request related to a problem? Please describe. The releases don't include a binary for Android.

    Describe the solution you'd like To change the workflow yaml to include it

    Describe alternatives you've considered My fork (https://github.com/denisidoro/static-web-server) includes it. I completely changed the yaml file to make it work, though. That's why I'm not submitting a pull request here: I suppose you'll want to add support for this with minimal changes.

    Additional context The binary can be used in e.g. Termux

    enhancement help wanted v2 target 
    opened by denisidoro 3
  • Support for Linux PowerPC (PPC64LE) and S390x targets

    Support for Linux PowerPC (PPC64LE) and S390x targets

    Description

    This PR adds support for PPC64LE Linux (ppc64le) and S390x Linux (s390x) targets.

    • linux/ppc64le: via powerpc64le-unknown-linux-gnu
    • linux/s390x: via s390x-unknown-linux-gnu

    Related Issue

    Motivation and Context

    How Has This Been Tested?

    Screenshots (if appropriate):

    enhancement release v2 dependency target 
    opened by joseluisq 1
  • Does not work with Let's encrypt generated .pem certificate files

    Does not work with Let's encrypt generated .pem certificate files

    Describe the bug

    Server runs on http as expected. I try to switch to https:

    #### HTTP/2 + TLS
    http2 = true
    http2-tls-cert = "/home/www/deployment/fullchain.pem"
    http2-tls-key =  "/home/www/deployment/privatkey.pem"
    

    I tried with with cert.pem, chain.pem as well - same error. Server does not start.

    To Reproduce

    1. Generate certificate files following: https://certbot.eff.org/instructions?ws=other&os=ubuntufocal
    2. Edit /dev/config.file like above, make sure paths are correct
    3. Run docker run --env SERVER_CONFIG_FILE=/config.toml -v /dev/config.toml:/config.toml -p 8787:80 joseluisq/static-web-server:2.12

    Expected behavior

    Webiste runts over https.

    Logs/Screenshots

    2022-09-29T22:32:19.848863Z  INFO static_web_server::server: config file: /config.toml
    2022-09-29T22:32:19.849055Z  INFO static_web_server::server: server bound to tcp socket [::]:8787
    2022-09-29T22:32:19.849092Z  INFO static_web_server::server: runtime worker threads: 2
    2022-09-29T22:32:19.849097Z  INFO static_web_server::server: security headers: enabled=true
    2022-09-29T22:32:19.849101Z  INFO static_web_server::server: auto compression: enabled=true
    2022-09-29T22:32:19.849104Z  INFO static_web_server::server: compression static: enabled=false
    2022-09-29T22:32:19.849108Z  INFO static_web_server::server: directory listing: enabled=false
    2022-09-29T22:32:19.849116Z  INFO static_web_server::server: directory listing order code: 6
    2022-09-29T22:32:19.849119Z  INFO static_web_server::server: cache control headers: enabled=true
    2022-09-29T22:32:19.849130Z  INFO static_web_server::server: basic authentication: enabled=false
    2022-09-29T22:32:19.849134Z  INFO static_web_server::server: log remote address: enabled=false
    2022-09-29T22:32:19.849137Z  INFO static_web_server::server: redirect trailing slash: enabled=true
    2022-09-29T22:32:19.849141Z  INFO static_web_server::server: grace period before graceful shutdown: 0s
    2022-09-29T22:32:19.849276Z ERROR static_web_server::server: server failed to start up: failed to initialize TLS probably because invalid cert or key file
    
    Caused by:
        certificate parse error
    

    Environment and Specs

    • static-web-server: v12.2
    • OS: Ubuntu 20.04 LTS
    • Docker: Docker version 19.03.8, build afacb8b7f0
    • Client: n/a

    Additional context

    Listing of the directory with files:

    www@broowqh:~/deployment$ ls -la
    total 52
    drwxr-xr-x  2 www www  4096 Sep 30 00:47 .
    drwxr-xr-x 12 www www  4096 Sep 29 22:48 ..
    -rw-r--r--  1 www root 5595 Sep 30 00:29 fullchain.pem
    -rw-r--r--  1 www root 1708 Sep 30 00:29 privkey.pem
    -rw-rw-r--  1 www www  1535 Sep 30 00:33 config.toml
    

    Docker is run by www user.

    Full config: https://pastebin.com/5XsbGVv4

    need-verification v2 
    opened by jkulak 2
  • Address family not supported by protocol (os error 97)

    Address family not supported by protocol (os error 97)

    Hi,

    server will not start if ipv6 is disabled

    ERROR static_web_server::server: server failed to start up: failed to bind to [::]:8787 address
    Caused by:
        Address family not supported by protocol (os error 97)
    

    it might be better to have a switch to disable ipv6 or at least handle such error in case ipv6 is not loaded

    and thank you for this library

    enhancement help wanted v2 
    opened by Abu-Abdullah 1
  • Simple prometheus metrics

    Simple prometheus metrics

    Is your feature request related to a problem? Please describe. I'd like to observe some minimal metrics.

    Describe the solution you'd like Expose prometheus metrics

    Describe alternatives you've considered Looking for a rust library to possibly plugin into.

    Additional context Add any other context or screenshots about the feature request here if needed.

    enhancement help wanted v2 
    opened by anthr76 0
  • 404 Page not change after server start

    404 Page not change after server start

    Describe the bug We have started the server, but the 404 error if you use a page that is not there, is only using the page version that is used on start. but not update it while you have changed the complete source.

    To Reproduce

    1. start server
    2. open not existing url
    3. change 404.html
    4. open another not existing url

    Expected behavior use the updated 404.html

    Logs/Screenshots If applicable, add logs or screenshots to help explain your problem.

    Environment and Specs

    • static-web-server: latest
    • OS: Ubuntu 20.04 with docker
    • Docker: latest
    • Client: latest chrome, latest firefox

    Additional context Add any other context about the problem here if needed.

    enhancement help wanted v2 
    opened by Dexus 3
Releases(v2.14.1)
Owner
Jose Quintana
Software Developer, GNU/Linux/BSD fan & FLOSS enthusiast. @rust-lang @golang @docker
Jose Quintana
🌟 For when you really just want to serve some files over HTTP right now!

miniserve - a CLI tool to serve files and dirs over HTTP For when you really just want to serve some files over HTTP right now! miniserve is a small,

Sven-Hendrik Haase 4.1k Dec 31, 2022
A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. :zap::crab:

binserve ⚡ ?? A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. ?? UPDATE: N

Mufeed VH 722 Dec 27, 2022
OxHTTP is a very simple synchronous HTTP client and server

OxHTTP is a very simple synchronous implementation of HTTP 1.1 in Rust. It provides both a client and a server.

Oxigraph 13 Nov 29, 2022
A starter template for actix-web projects that feels very Django-esque. Avoid the boring stuff and move faster.

Jelly A.K.A, the actix-web starter you probably wish you had. This is provided as-is, and anyone is free to extend it or rework it as they desire - ju

SecretKeys 198 Dec 15, 2022
VRS is a simple, minimal, free and open source static web server written in Rust

VRS is a simple, minimal, free and open source static web server written in Rust which uses absolutely no dependencies and revolves around Rust's std::net built-in utility.

null 36 Nov 8, 2022
Live Server - Launch a local network server with live reload feature for static pages

Live Server - Launch a local network server with live reload feature for static pages

Lomirus 18 Nov 30, 2022
simple static file server written in Rust based on axum framework

static-server simple static file server written in Rust based on axum framework I'm learning Rust and axum. My thought is simple. axum has a static-fi

null 27 Jan 1, 2023
Simple and fast web server

see Overview Simple and fast web server as a single executable with no extra dependencies required. Features Built with Tokio and Hyper TLS encryption

null 174 Dec 9, 2022
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust Features Supports HTTP/1.x and HTTP/2 Streaming and pipelining

Actix 16.3k Jan 8, 2023
Host These Things Please - a basic http server for hosting a folder fast and simply

http Host These Things Please - a basic HTTP server for hosting a folder fast and simply Selected features See the manpage for full list. Symlinks fol

thecoshman 367 Dec 23, 2022
Operator is a web server. You provide a directory and Operator serves it over HTTP.

Operator Operator is a web server. You provide a directory and Operator serves it over HTTP. It serves static files the way you'd expect, but it can a

Matt Kantor 6 Jun 6, 2022
Archibald is my attempt at learning Rust and writing a HTTP 1.1 web server.

Archibald To be a butler, is to be able to maintain an even-temper, at all times. One must have exceptional personal hygiene and look sharp and profes

Daniel Cuthbert 4 Jun 20, 2022
Salvo is a powerful and simplest web server framework in Rust world

Salvo is an extremely simple and powerful Rust web backend framework. Only basic Rust knowledge is required to develop backend services.

Salvo 1.2k Jan 5, 2023
A fast, boilerplate free, web framework for Rust

Tower Web A web framework for Rust with a focus on removing boilerplate. API Documentation Tower Web is: Fast: Fully asynchronous, built on Tokio and

Carl Lerche 969 Dec 22, 2022
web browser as a language server

web-browser-lsp A toy program that implements a text-based web browser as a language server. Motivation My favorite progrmming tools are neovim, tmux

octaltree 17 Nov 24, 2022
Web Server made with Rust - for learning purposes

Web Server made with Rust - for learning purposes

Lílian 2 Apr 25, 2022
Create, share, fetch and model Atomic Data! This project consists of a graph database + server, a CLI and a rust library.

Create, share, fetch and model Atomic Data! This repo consists of three components: A library, a server and a CLI. atomic-server Status: Beta. Breakin

Joep Meindertsma 195 Dec 28, 2022
Completely OBSOLETE Rust HTTP library (server and client)

OBSOLETION NOTICE This library is DEAD. It was a useful experiment and is now being replaced under the scope of the Teepee (experimentation grounds at

Chris Morgan 390 Dec 1, 2022
:zap: fast http framework for rust

zap ⚡ The mission of zap is, to deliver a basic, but fast rust web server library. Documentation About This code is based on tokio's minihttp project,

Daniel Oltmanns 51 Jun 7, 2022